Railway Operation Simulator  v2.10.0
A railway simulator for Windows
InterfaceUnit2.10.0.cpp
Go to the documentation of this file.
1 // InterfaceUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 
27 #include <Classes.hpp>
28 #include <Controls.hpp>
29 #include <StdCtrls.hpp>
30 #include <Forms.hpp>
31 #include <Buttons.hpp>
32 #include <ExtCtrls.hpp>
33 #include <Menus.hpp>
34 #include <Dialogs.hpp>
35 #include <Graphics.hpp>
36 #include <ComCtrls.hpp>
37 #include <Clipbrd.hpp> //for selection clipboard functions at v2.8.0
38 #include <fstream>
39 #include <sstream> //for clipboard functions at v2.8.0
40 #include <vector>
41 #include <vcl.h>
42 #include <stdio.h>
43 #include <algorithm> //for sort
44 
45 #pragma hdrstop
46 // The above batch of include files above #pragma hdrstop appear in all .cpp files.
47 // They aren't all needed in each case but being together and identical they speed
48 // up compilation considerably (without ~14 min, with ~1 min!). They are used in
49 // conjunction with 'use pre-compiled headers' in the project compiler options.
50 
51 #include "InterfaceUnit.h"
52 #include "GraphicUnit.h"
53 #include "DisplayUnit.h"
54 #include "TextUnit.h"
55 #include "TrainUnit.h"
56 #include "Utilities.h"
57 #include "TrackUnit.h"
58 #include "AboutUnit.h"
59 #include "API.h" //added at v2.10.0
60 #include <dirent.h>
61 #include <Filectrl.hpp> //to check whether directories exist
62 
63 // ---------------------------------------------------------------------------
64 #include <Vcl.HTMLHelpViewer.hpp> //added at v2.0.0 for access to the .chm help file
65 #pragma package(smart_init)
66 #pragma link "Vcl.HTMLHelpViewer" //added at v2.0.0 for access to the .chm help file
67 #pragma resource "*.dfm"
68 
70 API *session_api_; //moved from header to avoid AboutForm having access and defining _session_api_
71  //as well as Interface and giving a warning, added at v2.10.0
72 
73 // Folder Names
74 const UnicodeString TInterface::RAILWAY_DIR_NAME = "Railways";
75 const UnicodeString TInterface::TIMETABLE_DIR_NAME = "Program timetables";
76 const UnicodeString TInterface::PERFLOG_DIR_NAME = "Performance logs";
77 const UnicodeString TInterface::SESSION_DIR_NAME = "Sessions";
78 const UnicodeString TInterface::IMAGE_DIR_NAME = "Images";
79 const UnicodeString TInterface::FORMATTEDTT_DIR_NAME = "Formatted timetables";
80 const UnicodeString TInterface::USERGRAPHICS_DIR_NAME = "Graphics";
81 
82 // ---------------------------------------------------------------------------
83 
84 __fastcall TInterface::TInterface(TComponent* Owner) : TForm(Owner)
85 {
86  // constructor
87  try
88  {
89  Screen->Cursor = TCursor(-11); // Hourglass
90  DirOpenError = false;
91  AllSetUpFlag = false; // flag to prevent MasterClock from being enabled when application activates if there has been an error during
92  // initial setup
93  // MasterClock->Enabled = false;//keep this stopped until all set up (no effect here as form not yet created, made false in object insp)
94  // Visible = false; //keep the Interface form invisible until all set up (no effect here as form not yet created, made false in object insp)
95  ProgramVersion = GetVersion();
96  // use GNU Major/Minor/Patch version numbering system, change for each published modification, Dev x = interim internal
97  // development stages (don't show on published versions)
98 
99  // check for presence of directories, creation failure probably indicates that the
100  // working folder is read-only
101 
102  CurDir = AnsiString(GetCurrentDir());
103 // ShowMessage("Curdir from GetCurrentDir() " + CurDir); //these used to check behaviour outside the compiler
104  UnicodeString FullProgramName = GetModuleName(0); // added at v2.9.0 to check executable exists
105 // ShowMessage("FullProgramName " + FullProgramName);
106  UnicodeString ProgramName = ExtractFileName(FullProgramName); // as above
107 // ShowMessage("ProgramName " + ProgramName);
108  UnicodeString ProgramDirectoryName = ExtractFilePath(FullProgramName); // as above
109 // ShowMessage("ProgramDirectoryName " + ProgramDirectoryName);
110 
111  if(!FileExists(ProgramName)) //added at v2.9.0 after discovering the effect described below
112  {
113  if(!SetCurrentDir(ProgramDirectoryName)) //if false the current directory couldn't be changed
114  {
115  ShowMessage("The working directory does not contain the railway executable file so the program cannot "
116  "open. This is usually because the program has been selected via the right-click taskbar icon though it may "
117  "also happen in other circumstances. It is caused by the Windows operating system re-assigning the "
118  "working directory for some unknown reason, though whether or not it happens appears to depend on the "
119  "Windows update version.\n\n"
120  "To avoid this happening please open the program by double clicking the program icon on the desktop "
121  "if there is one, or the program icon shown in Windows Explorer.");
122  Application->Terminate();
123  }
124  else
125  {
126  CurDir = AnsiString(GetCurrentDir());
127  }
128  }
129 
130  if(!DirectoryExists(RAILWAY_DIR_NAME))
131  {
132  if(!CreateDir(RAILWAY_DIR_NAME))
133  {
134  DirOpenError = true;
135  }
136 
137  }
138  if(!DirectoryExists(TIMETABLE_DIR_NAME))
139  {
140  if(!CreateDir(TIMETABLE_DIR_NAME))
141  {
142  DirOpenError = true;
143  }
144  }
145  if(!DirectoryExists(PERFLOG_DIR_NAME))
146  {
147  if(!CreateDir(PERFLOG_DIR_NAME))
148  {
149  DirOpenError = true;
150  }
151  }
152  if(!DirectoryExists(SESSION_DIR_NAME))
153  {
154  if(!CreateDir(SESSION_DIR_NAME))
155  {
156  DirOpenError = true;
157  }
158  }
159  if(!DirectoryExists(IMAGE_DIR_NAME))
160  {
161  if(!CreateDir(IMAGE_DIR_NAME))
162  {
163  DirOpenError = true;
164  }
165  }
166  if(!DirectoryExists(FORMATTEDTT_DIR_NAME))
167  {
168  if(!CreateDir(FORMATTEDTT_DIR_NAME))
169  {
170  DirOpenError = true;
171  }
172  }
173  if(!DirectoryExists(USERGRAPHICS_DIR_NAME))
174  {
175  if(!CreateDir(USERGRAPHICS_DIR_NAME))
176  {
177  DirOpenError = true;
178  }
179  }
180  if(DirOpenError)
181  {
182  ShowMessage("Failed to create one or more of folders: " + RAILWAY_DIR_NAME + ", " + TIMETABLE_DIR_NAME + ", " + PERFLOG_DIR_NAME + ", " +
183  SESSION_DIR_NAME + ", " + IMAGE_DIR_NAME + ", " + FORMATTEDTT_DIR_NAME + ", " + USERGRAPHICS_DIR_NAME + ", " +
184  "program operation will be restricted");
185  }
186  Application->HelpFile = AnsiString(CurDir + "\\Help.chm"); // added at v2.0.0 for .chm help file
187 
188  MainMenu1->AutoHotkeys = maManual; // Embarcadero mod: to suppress '&' inclusion for underlined characters in menu items
189  PopupMenu->AutoHotkeys = maManual; // as above
190 
191  Utilities = new TUtilities;
192  RailGraphics = new TRailGraphics();
193 
194  int DispW = (Screen->Width - 64) / 16; // will truncate down to a multiple of 16 OK here as screen dimensions are accurate
195  int DispH = (Screen->Height - 192) / 16; // Interface dimensions are 16 too wide & 14 short in height
196  MainScreen->Width = DispW * 16;
197  MainScreen->Height = DispH * 16;
198 
199  Display = new TDisplay(MainScreen, PerformanceLogBox, OutputLog1, OutputLog2, OutputLog3, OutputLog4, OutputLog5, OutputLog6, OutputLog7, OutputLog8,
200  OutputLog9, OutputLog10);
201  Utilities->ScreenElementWidth = DispW;
203  HiddenScreen = new TImage(Interface);
204  HiddenScreen->Width = MainScreen->Width;
205  HiddenScreen->Height = MainScreen->Height;
206  HiddenDisplay = new TDisplay(HiddenScreen, PerformanceLogBox, OutputLog1, OutputLog2, OutputLog3, OutputLog4, OutputLog5, OutputLog6, OutputLog7,
207  OutputLog8, OutputLog9, OutputLog10);
209  Track = new TTrack;
210  AllRoutes = new TAllRoutes;
211  ConstructPrefDir = new TOnePrefDir;
212  ConstructRoute = new TOneRoute;
213  EveryPrefDir = new TOnePrefDir;
214  SelectPrefDir = new TOnePrefDir;
216  SelectBitmap = new Graphics::TBitmap;
217  SelectBitmap->PixelFormat = pf8bit;
218  SelectBitmap->Transparent = true;
219  PointFlash = new TGraphicElement;
220  AutoRouteStartMarker = new TGraphicElement;
221  SigRouteStartMarker = new TGraphicElement;
222  NonSigRouteStartMarker = new TGraphicElement;
223  LengthWarningSentFlag = false;
224  PasteWarningSentFlag = false; // added at v2.6.0
225  FillSelectionMessageSentFlag = false; // added at v2.6.0
226  LCManualLowerBarriersMessageSent = false; // added at v2.6.0
227  RecoverClipboardMessageSent = false; // added at v2.8.0
228  TooLongMessageSentFlag = false; //added at v2.9.1
229  TooShortMessageSentFlag = false; //added at v2.9.1
230  Track->NoPlatsMessageSent = false; //added at v2.10.0
231 
232  TrackInfoOnOffMenuItem->Caption = "Show"; // added here at v1.2.0 because dropped from ResetAll()
233  TrainStatusInfoOnOffMenuItem->Caption = "Hide Status"; // changed at v2.0.0 so normally visible
234  TrainTTInfoOnOffMenuItem->Caption = "Hide Timetable"; // as above
235 
236  /* ======================= ROS Dummy API ===============================
237  Connect API to track variables of interest, added at v2.10.0
238  */
239  session_api_ = new API(CurDir + "\\session.ini");
240  session_api_->add_metadata_str("railway", &RailwayTitle);
241  session_api_->add_metadata_str("timetable", &TimetableTitle);
242  session_api_->add_metadata_str("performance_file", &PerformanceFileName);
243  session_api_->add_metadata_int("main_mode", &api_main_mode_);
244  session_api_->add_metadata_int("operation_mode", &api_oper_mode_);
245 
246  // =====================================================================
247 
248  ResetAll(0);
249 
250  TempTTFileName = "";
251 
252  PointFlash->LoadOverlayGraphic(3, RailGraphics->bmGreenRect);
253  AutoRouteStartMarker->LoadOverlayGraphic(4, RailGraphics->bmLightBlueRect);
254  SigRouteStartMarker->LoadOverlayGraphic(5, RailGraphics->bmGreenRect);
255  NonSigRouteStartMarker->LoadOverlayGraphic(6, RailGraphics->bmRedRect);
256 
257  RouteFlashDuration = 0.0;
258  PointsFlashDuration = 0.0;
259 
260  FloatingLabel->Color = clB4G5R5;
261  TrackElementPanel->Color = clB5G5R4;
262  InfoPanel->Color = clB4G5R5;
263 
264  LoadUserGraphicDialog->InitialDir = CurDir + "\\" + USERGRAPHICS_DIR_NAME; // not changeable
265 
266  Utilities->RHSignalFlag = false; // new at v2.3.0 for RH signals, always left hand on startup
267  SigsOnLeftImage1->Picture->Bitmap->LoadFromResourceName(0, "SigsOnLeft");
268  SigsOnLeftImage2->Picture->Bitmap->LoadFromResourceName(0, "SigsOnLeft");
269  SigsOnLeftImage1->Transparent = true;
270  SigsOnLeftImage2->Transparent = true;
271  SigsOnLeftImage1->Picture->Bitmap->TransparentColor = clB5G5R5;
272  SigsOnLeftImage2->Picture->Bitmap->TransparentColor = clB5G5R5;
273  SigsOnRightImage1->Picture->Bitmap->LoadFromResourceName(0, "SigsOnRight");
274  SigsOnRightImage2->Picture->Bitmap->LoadFromResourceName(0, "SigsOnRight");
275  SigsOnRightImage1->Transparent = true;
276  SigsOnRightImage2->Transparent = true;
277  SigsOnRightImage1->Picture->Bitmap->TransparentColor = clB5G5R5;
278  SigsOnRightImage2->Picture->Bitmap->TransparentColor = clB5G5R5;
279 
280  SaveRailwayDialog->InitialDir = CurDir + "\\" + RAILWAY_DIR_NAME; // default locations if not updated from Config.txt
281  LoadRailwayDialog->InitialDir = CurDir + "\\" + RAILWAY_DIR_NAME;
282  TimetableDialog->InitialDir = CurDir + "\\" + TIMETABLE_DIR_NAME;
283  SaveTTDialog->InitialDir = CurDir + "\\" + TIMETABLE_DIR_NAME;
284  LoadSessionDialog->InitialDir = CurDir + "\\" + SESSION_DIR_NAME;
285 
286  std::ifstream ConfigFile((CurDir + "\\Config.txt").c_str()); // added at v2.6.0 to set save & load directories for railways, timetables & session & to
287  if(ConfigFile.fail()) // no Config file //replace Signal.hnd, Background.col and GNU
288  {
289  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
290  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
291  SigsOnLeftImage1->Visible = true;
292  SigsOnLeftImage2->Visible = true;
293  SigsOnRightImage1->Visible = false;
294  SigsOnRightImage2->Visible = false;
295  ShowMessage(
296  "This program is free software released under the terms of the GNU General Public License Version 3, as published by the Free Software Foundation. " "It may be used or redistributed in accordance with that license and is released in the hope that it will be useful, but WITHOUT ANY WARRANTY; "
297  "without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details - " "you should have received a copy along with this program but if not see <http://www.gnu.org/licenses/>."
298  );
299  }
300  else
301  {
302  AnsiString ConfigStr = "";
303  do
304  {
305  Utilities->CheckAndReadFileString(ConfigFile, ConfigStr);
306  if(ConfigFile.eof())
307  {
308  break;
309  }
310  AnsiString ConfigValue = ConfigStr.SubString(9, ConfigStr.Length() - 8);
311  if(ConfigStr.SubString(1, 8) == "Signals=")
312  {
313  if(ConfigValue == "right")
314  {
315  RailGraphics->ConvertSignalsToOppositeHand(1); // always left hand initially when start program, toggles Utilities->RHSignalFlag
316  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Left Hand Signals";
318  {
319  LoadGroundSignalGlyphs(1);
320  }
321  else
322  {
323  LoadNormalSignalGlyphs(1);
324  }
325  SigImagePanel->Caption = "Signals will be on the right hand side of the track";
326  SigsOnLeftImage1->Visible = false;
327  SigsOnLeftImage2->Visible = false;
328  SigsOnRightImage1->Visible = true;
329  SigsOnRightImage2->Visible = true;
330  }
331  else
332  {
333  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
334  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
335  SigsOnLeftImage1->Visible = true;
336  SigsOnLeftImage2->Visible = true;
337  SigsOnRightImage1->Visible = false;
338  SigsOnRightImage2->Visible = false;
339  }
340  }
341  if(ConfigStr.SubString(1, 8) == "BgndCol=")
342  {
343  // pick up transparent colour from file if there is one & set it to the stored value if it's valid else set to black
344  Utilities->clTransparent = clB0G0R0; // default black background;
345  if(ConfigValue == "white")
346  {
347  Utilities->clTransparent = TColor(0xFFFFFF);
348  }
349  else if(ConfigValue == "blue")
350  {
351  Utilities->clTransparent = TColor(0x330000);
352  }
353  }
354  if(ConfigStr.SubString(1, 8) == "RLYLocn=")
355  {
356  if(DirectoryExists(ConfigValue)) // e;se stays as original directory
357  {
358  SaveRailwayDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
359  LoadRailwayDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
360  }
361  }
362  else if(ConfigStr.SubString(1, 8) == "TTBLocn=")
363  {
364  if(DirectoryExists(ConfigValue)) // e;se stays as original directory
365  {
366  TimetableDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
367  SaveTTDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
368  }
369  }
370  else if(ConfigStr.SubString(1, 8) == "SSNLocn=")
371  {
372  if(DirectoryExists(ConfigValue)) // e;se stays as original directory
373  {
374  LoadSessionDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
375  }
376  }
377  }
378  while(!ConfigFile.eof());
379  ConfigFile.close();
380  }
381  SpeedButton1->Glyph->LoadFromResourceName(0, "gl1");
382  SpeedButton2->Glyph->LoadFromResourceName(0, "gl2");
383  SpeedButton3->Glyph->LoadFromResourceName(0, "gl3");
384  SpeedButton4->Glyph->LoadFromResourceName(0, "gl4");
385  SpeedButton5->Glyph->LoadFromResourceName(0, "gl5");
386  SpeedButton6->Glyph->LoadFromResourceName(0, "gl6");
387  SpeedButton7->Glyph->LoadFromResourceName(0, "gl7");
388  SpeedButton8->Glyph->LoadFromResourceName(0, "gl8");
389  SpeedButton9->Glyph->LoadFromResourceName(0, "gl9");
390  SpeedButton10->Glyph->LoadFromResourceName(0, "gl10");
391  SpeedButton11->Glyph->LoadFromResourceName(0, "gl11");
392  SpeedButton12->Glyph->LoadFromResourceName(0, "gl12");
393  SpeedButton13->Glyph->LoadFromResourceName(0, "gl13");
394  SpeedButton14->Glyph->LoadFromResourceName(0, "gl14");
395  SpeedButton15->Glyph->LoadFromResourceName(0, "gl15");
396  SpeedButton16->Glyph->LoadFromResourceName(0, "gl16");
397  SpeedButton18->Glyph->LoadFromResourceName(0, "gl18");
398  SpeedButton19->Glyph->LoadFromResourceName(0, "gl19");
399  SpeedButton20->Glyph->LoadFromResourceName(0, "gl20");
400  SpeedButton21->Glyph->LoadFromResourceName(0, "gl21");
401  SpeedButton22->Glyph->LoadFromResourceName(0, "gl22");
402  SpeedButton23->Glyph->LoadFromResourceName(0, "gl23");
403  SpeedButton24->Glyph->LoadFromResourceName(0, "gl24");
404  SpeedButton25->Glyph->LoadFromResourceName(0, "gl25");
405  SpeedButton26->Glyph->LoadFromResourceName(0, "gl26");
406  SpeedButton27->Glyph->LoadFromResourceName(0, "gl27");
407  SpeedButton28->Glyph->LoadFromResourceName(0, "gl28");
408  SpeedButton29->Glyph->LoadFromResourceName(0, "gl29");
409  SpeedButton30->Glyph->LoadFromResourceName(0, "gl30");
410  SpeedButton31->Glyph->LoadFromResourceName(0, "gl31");
411  SpeedButton32->Glyph->LoadFromResourceName(0, "gl32");
412  SpeedButton33->Glyph->LoadFromResourceName(0, "gl33");
413  SpeedButton34->Glyph->LoadFromResourceName(0, "gl34");
414  SpeedButton35->Glyph->LoadFromResourceName(0, "gl35");
415  SpeedButton36->Glyph->LoadFromResourceName(0, "gl36");
416  SpeedButton37->Glyph->LoadFromResourceName(0, "gl37");
417  SpeedButton38->Glyph->LoadFromResourceName(0, "gl38");
418  SpeedButton39->Glyph->LoadFromResourceName(0, "gl39");
419  SpeedButton40->Glyph->LoadFromResourceName(0, "gl40");
420  SpeedButton41->Glyph->LoadFromResourceName(0, "gl41");
421  SpeedButton42->Glyph->LoadFromResourceName(0, "gl42");
422  SpeedButton43->Glyph->LoadFromResourceName(0, "gl43");
423  SpeedButton44->Glyph->LoadFromResourceName(0, "gl44");
424  SpeedButton45->Glyph->LoadFromResourceName(0, "gl45");
425  SpeedButton46->Glyph->LoadFromResourceName(0, "gl46");
426  SpeedButton47->Glyph->LoadFromResourceName(0, "gl47");
427  SpeedButton48->Glyph->LoadFromResourceName(0, "gl48");
428  SpeedButton49->Glyph->LoadFromResourceName(0, "gl49");
429  SpeedButton50->Glyph->LoadFromResourceName(0, "gl50");
430  SpeedButton51->Glyph->LoadFromResourceName(0, "gl51");
431  SpeedButton52->Glyph->LoadFromResourceName(0, "gl52");
432  SpeedButton53->Glyph->LoadFromResourceName(0, "gl53");
433  SpeedButton54->Glyph->LoadFromResourceName(0, "gl54");
434  SpeedButton55->Glyph->LoadFromResourceName(0, "gl55");
435  SpeedButton56->Glyph->LoadFromResourceName(0, "gl56");
436  SpeedButton57->Glyph->LoadFromResourceName(0, "gl57");
437  SpeedButton58->Glyph->LoadFromResourceName(0, "gl58");
438  SpeedButton59->Glyph->LoadFromResourceName(0, "gl59");
439  SpeedButton60->Glyph->LoadFromResourceName(0, "gl60");
440  SpeedButton61->Glyph->LoadFromResourceName(0, "gl61");
441  SpeedButton62->Glyph->LoadFromResourceName(0, "gl62");
442  SpeedButton63->Glyph->LoadFromResourceName(0, "gl63");
443  SpeedButton64->Glyph->LoadFromResourceName(0, "gl64");
444  SpeedButton65->Glyph->LoadFromResourceName(0, "gl65");
445  SpeedButton66->Glyph->LoadFromResourceName(0, "gl66");
446  SpeedButton67->Glyph->LoadFromResourceName(0, "gl67");
447  SpeedButton68->Glyph->LoadFromResourceName(0, "gl68");
448  SpeedButton69->Glyph->LoadFromResourceName(0, "gl69");
449  SpeedButton70->Glyph->LoadFromResourceName(0, "gl70");
450  SpeedButton71->Glyph->LoadFromResourceName(0, "gl71");
451  SpeedButton72->Glyph->LoadFromResourceName(0, "gl72");
452  SpeedButton73->Glyph->LoadFromResourceName(0, "gl73");
453  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74");
454  SpeedButton75->Glyph->LoadFromResourceName(0, "gl75");
455  SpeedButton76->Glyph->LoadFromResourceName(0, "gl76");
456  SpeedButton77->Glyph->LoadFromResourceName(0, "gl77");
457  SpeedButton78->Glyph->LoadFromResourceName(0, "gl78");
458  SpeedButton79->Glyph->LoadFromResourceName(0, "gl79");
459  SpeedButton80->Glyph->LoadFromResourceName(0, "gl80");
460  SpeedButton81->Glyph->LoadFromResourceName(0, "gl81");
461  SpeedButton82->Glyph->LoadFromResourceName(0, "gl82");
462  SpeedButton83->Glyph->LoadFromResourceName(0, "gl83");
463  SpeedButton84->Glyph->LoadFromResourceName(0, "gl84");
464  SpeedButton85->Glyph->LoadFromResourceName(0, "gl85");
465  SpeedButton86->Glyph->LoadFromResourceName(0, "gl86");
466  SpeedButton87->Glyph->LoadFromResourceName(0, "gl87");
467  SpeedButton88->Glyph->LoadFromResourceName(0, "gl88set");
468  SpeedButton89->Glyph->LoadFromResourceName(0, "gl89set");
469  SpeedButton90->Glyph->LoadFromResourceName(0, "gl90set");
470  SpeedButton91->Glyph->LoadFromResourceName(0, "gl91set");
471  SpeedButton92->Glyph->LoadFromResourceName(0, "gl92set");
472  SpeedButton93->Glyph->LoadFromResourceName(0, "gl93set");
473  SpeedButton94->Glyph->LoadFromResourceName(0, "gl94set");
474  SpeedButton95->Glyph->LoadFromResourceName(0, "gl95set");
475  SpeedButton96->Glyph->LoadFromResourceName(0, "ConcourseGlyph");
476  SpeedButton97->Glyph->LoadFromResourceName(0, "gl97");
477  SpeedButton98->Glyph->LoadFromResourceName(0, "gl98");
478  SpeedButton99->Glyph->LoadFromResourceName(0, "gl99");
479  SpeedButton100->Glyph->LoadFromResourceName(0, "gl100");
480  SpeedButton101->Glyph->LoadFromResourceName(0, "gl101");
481  SpeedButton102->Glyph->LoadFromResourceName(0, "gl102");
482  SpeedButton103->Glyph->LoadFromResourceName(0, "gl103");
483  SpeedButton104->Glyph->LoadFromResourceName(0, "gl104");
484  SpeedButton105->Glyph->LoadFromResourceName(0, "gl105");
485  SpeedButton106->Glyph->LoadFromResourceName(0, "gl106");
486  SpeedButton107->Glyph->LoadFromResourceName(0, "gl107");
487  SpeedButton108->Glyph->LoadFromResourceName(0, "gl108");
488  SpeedButton109->Glyph->LoadFromResourceName(0, "gl109");
489  SpeedButton110->Glyph->LoadFromResourceName(0, "gl110");
490  SpeedButton111->Glyph->LoadFromResourceName(0, "gl111");
491  SpeedButton112->Glyph->LoadFromResourceName(0, "gl112");
492  SpeedButton113->Glyph->LoadFromResourceName(0, "gl113");
493  SpeedButton114->Glyph->LoadFromResourceName(0, "gl114");
494  SpeedButton115->Glyph->LoadFromResourceName(0, "gl115");
495  SpeedButton116->Glyph->LoadFromResourceName(0, "gl116");
496  SpeedButton117->Glyph->LoadFromResourceName(0, "gl117");
497  SpeedButton118->Glyph->LoadFromResourceName(0, "gl118");
498  SpeedButton119->Glyph->LoadFromResourceName(0, "gl119");
499  SpeedButton120->Glyph->LoadFromResourceName(0, "gl120");
500  SpeedButton121->Glyph->LoadFromResourceName(0, "gl121");
501  SpeedButton122->Glyph->LoadFromResourceName(0, "gl122");
502  SpeedButton123->Glyph->LoadFromResourceName(0, "gl123");
503  SpeedButton124->Glyph->LoadFromResourceName(0, "gl124");
504  SpeedButton125->Glyph->LoadFromResourceName(0, "gl125");
505  SpeedButton126->Glyph->LoadFromResourceName(0, "gl126");
506  SpeedButton127->Glyph->LoadFromResourceName(0, "gl127");
507  SpeedButton128->Glyph->LoadFromResourceName(0, "gl128");
508  SpeedButton129->Glyph->LoadFromResourceName(0, "gl129");
509  SpeedButton130->Glyph->LoadFromResourceName(0, "gl130");
510  SpeedButton131->Glyph->LoadFromResourceName(0, "gl131");
511  SpeedButton132->Glyph->LoadFromResourceName(0, "gl132");
512  SpeedButton133->Glyph->LoadFromResourceName(0, "gl133");
513  SpeedButton134->Glyph->LoadFromResourceName(0, "gl134");
514  SpeedButton135->Glyph->LoadFromResourceName(0, "gl135");
515  SpeedButton136->Glyph->LoadFromResourceName(0, "gl136");
516  SpeedButton137->Glyph->LoadFromResourceName(0, "gl137");
517  SpeedButton138->Glyph->LoadFromResourceName(0, "gl138");
518  SpeedButton139->Glyph->LoadFromResourceName(0, "gl139");
519  SpeedButton140->Glyph->LoadFromResourceName(0, "gl140");
520  SpeedButton141->Glyph->LoadFromResourceName(0, "gl141");
521  SpeedButton142->Glyph->LoadFromResourceName(0, "gl142");
522  SpeedButton143->Glyph->LoadFromResourceName(0, "gl143");
523  SpeedButton145->Glyph->LoadFromResourceName(0, "gl145");
524  SpeedButton146->Glyph->LoadFromResourceName(0, "gl146");
525  // below not in RailGraphics
526  SpeedButton144->Glyph->LoadFromResourceName(0, "LCGlyph");
527 
528  AddPrefDirButton->Glyph->LoadFromResourceName(0, "AddPrefDir");
529  AddTextButton->Glyph->LoadFromResourceName(0, "AddText");
530  AddTrackButton->Glyph->LoadFromResourceName(0, "AddTrack");
531  AutoSigsButton->Glyph->LoadFromResourceName(0, "AutoSig");
532  CallingOnButton->Glyph->LoadFromResourceName(0, "CallingOn");
533  DeleteAllPrefDirButton->Glyph->LoadFromResourceName(0, "ClearAllPrefDir");
534  DeleteOnePrefDirButton->Glyph->LoadFromResourceName(0, "ClearOnePrefDir");
535  ExitOperationButton->Glyph->LoadFromResourceName(0, "Exit");
536  ExitPrefDirButton->Glyph->LoadFromResourceName(0, "Exit");
537  ExitTrackButton->Glyph->LoadFromResourceName(0, "Exit");
538  ExitTTModeButton->Glyph->LoadFromResourceName(0, "Exit");
539  FontButton->Glyph->LoadFromResourceName(0, "FontGraphic");
540  HomeButton->Glyph->LoadFromResourceName(0, "Home");
541  LocationNameButton->Glyph->LoadFromResourceName(0, "NameLocs");
542  MoveTextOrGraphicButton->Glyph->LoadFromResourceName(0, "MoveTextOrGraphic");
543  NewHomeButton->Glyph->LoadFromResourceName(0, "NewHome");
544  UnrestrictedButton->Glyph->LoadFromResourceName(0, "NonSig");
545  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
546  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel");
547  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
548  PresetAutoSigRoutesButton->Glyph->LoadFromResourceName(0, "PresetAutoSigRoutes");
549  RouteCancelButton->Glyph->LoadFromResourceName(0, "RouteCancel");
550  SaveRailwayPDPButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // PrefDirPanel
551  SaveRailwayBaseModeButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // OperatingPanel
552  SaveRailwayTBPButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // TrackBuildPanel
553  SaveSessionButton->Glyph->LoadFromResourceName(0, "SaveSession");
554  ScreenDownButton->Glyph->LoadFromResourceName(0, "BlackArrowDown");
555  ScreenGridButton->Glyph->LoadFromResourceName(0, "ScreenGrid");
556  ScreenLeftButton->Glyph->LoadFromResourceName(0, "BlackArrowLeft");
557  ScreenRightButton->Glyph->LoadFromResourceName(0, "BlackArrowRight");
558  ScreenUpButton->Glyph->LoadFromResourceName(0, "BlackArrowUp");
559  SetGapsButton->Glyph->LoadFromResourceName(0, "ConnectGaps");
560  SetLengthsButton->Glyph->LoadFromResourceName(0, "SetDists");
561  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
562  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect"); // new at version 0.6
563  SigPrefConsecButton->Glyph->LoadFromResourceName(0, "PrefTop");
564  SigPrefNonConsecButton->Glyph->LoadFromResourceName(0, "PrefBottom");
565  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
566  TrackOKButton->Glyph->LoadFromResourceName(0, "Validate");
567  TTClockAdjButton->Glyph->LoadFromResourceName(0, "TTClock");
568  UserGraphicButton->Glyph->LoadFromResourceName(0, "PictureImage");
569 
570  BufferAttentionImage->Picture->Bitmap->LoadFromResourceName(0, "BufferWarning");
571  CallOnImage->Picture->Bitmap->LoadFromResourceName(0, "CallingOn");
572  CrashImage->Picture->Bitmap->LoadFromResourceName(0, "CrashWarning");
573  DerailImage->Picture->Bitmap->LoadFromResourceName(0, "DerailWarning");
574  SignalStopImage->Picture->Bitmap->LoadFromResourceName(0, "SignalStopWarning");
575  SPADImage->Picture->Bitmap->LoadFromResourceName(0, "SPADWarning");
576  TrainFailedImage->Picture->Bitmap->LoadFromResourceName(0, "TrainFailedWarning"); // new at v2.4.0
577  ManualLCDownImage->Picture->Bitmap->LoadFromResourceName(0, "ManualLCDownImage"); // new at v2.9.0
578 
579  DistanceKey->Picture->Bitmap->LoadFromResourceName(0, "DistanceKey");
580  PrefDirKey->Picture->Bitmap->LoadFromResourceName(0, "PrefDirKey");
581 
582  TrackLinkedImage->Picture->Bitmap->LoadFromResourceName(0, "TrackLinkedGraphic");
583  TrackNotLinkedImage->Picture->Bitmap->LoadFromResourceName(0, "TrackNotLinkedGraphic");
584  GapsNotSetImage->Picture->Bitmap->LoadFromResourceName(0, "GapsNotSetGraphic");
585  GapsSetImage->Picture->Bitmap->LoadFromResourceName(0, "GapsSetGraphic");
586  LocationNamesNotSetImage->Picture->Bitmap->LoadFromResourceName(0, "LocNamesNotSetGraphic");
587  LocationNamesSetImage->Picture->Bitmap->LoadFromResourceName(0, "LocNamesSetGraphic");
588 
589 /* Don't need this - load icon directly into both Interface form & Application (via Project - Options - Application - Load Icon)
590  RailwayIcon = new TPicture;
591  RailwayIcon->Icon->LoadFromResourceName(0, "Icon1.ico");
592  Icon = RailwayIcon->Icon;
593  Application->Icon = RailwayIcon->Icon;
594 */
595 
596  AnsiString NL = '\n';
597  const AnsiString TTLabelStr1 = "Start new train" + NL + "Start new service from a split" + NL + "Start new service from another service" + NL +
598  "Start new non-repeating shuttle finish service" + NL + "Start new shuttle train at a timetabled stop" + NL +
599  "Start new shuttle service from a feeder";
600 
601  const AnsiString TTLabelStr2 = "Pass" + NL + "Be joined by another train" + NL + "Front split" + NL + "Rear split" + NL + "Change direction of train";
602 
603  const AnsiString TTLabelStr3 = "Finish && form a new service" + NL + "Finish && join another train" + NL + "Finish && exit railway" + NL +
604  "Finish && repeat shuttle, finally remain here" + NL + "Finish && repeat shuttle, finally form a finishing service" + NL +
605  "Finish non-repeating shuttle feeder service" + NL + "Finish && remain here";
606 
607  const AnsiString TTLabelStr4 = "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL +
608  "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + " " +
609  NL + "R";
610 
611  const AnsiString TTLabelStr5 = "HH:MM ';' Location" + NL + "HH:MM ';' HH:MM ';' Location";
612 
613  const AnsiString TTLabelStr6 = "+ rear element ID - space - front element ID [+ optional ';S']" + NL + "+ ref. of the train that splits" + NL +
614  "+ other service ref." + NL + "+ shuttle service ref." + NL + "+ rear element ID - space - front element ID ';' linked shuttle ref." + NL +
615  "+ linked shuttle service ref. ';' feeder service ref." + NL + "+ location" + NL + "+ joining train ref." + NL + "+ new service ref." + NL +
616  "+ new service ref." + NL + " " + NL + "+ new service ref." + NL + "+ ref. of train to join" + NL +
617  "+ list of valid exit element IDs (at least 1) separated by spaces" + NL + "+ linked shuttle service ref.";
618 
619  const AnsiString TTLabelStr7 = "Arrival OR departure time (program will determine which from the context) + location." + NL +
620  "Arrival time, departure time (with no events between) + location";
621 
622  const AnsiString TTLabelStr9 = "Timetable entries" + NL + "(service references etc.)";
623  const AnsiString TTLabelStr11 = "Timetable" + NL + "start time";
624 
625  const AnsiString TTLabelStr12 = "NB: WITHIN SERVICES commas must" + NL + "not be used (have special meanings)," + NL +
626  "and semicolons may only be used to" + NL + "separate service components.";
627 
628  const AnsiString TTLabelStr13 = "+ linked shuttle service ref. ';' finishing service ref." + NL + "+ linked shuttle service ref.";
629 
630  const AnsiString TTLabelStr15 = "Repeat the service + ';' minutes between repeats ';' digit increment ';' number of repeats (last line of service)";
631 
632  TTLabel1->Caption = TTLabelStr1;
633  TTLabel2->Caption = TTLabelStr2;
634  TTLabel3->Caption = TTLabelStr3;
635  TTLabel4->Caption = TTLabelStr4;
636  TTLabel5->Caption = TTLabelStr5;
637  TTLabel6->Caption = TTLabelStr6;
638  TTLabel7->Caption = TTLabelStr7;
639  TTLabel9->Caption = TTLabelStr9;
640  TTLabel11->Caption = TTLabelStr11;
641  TTLabel12->Caption = TTLabelStr12;
642  TTLabel13->Caption = TTLabelStr13;
643  TTLabel15->Caption = TTLabelStr15;
644 
645  SelectBitmap->TransparentColor = Utilities->clTransparent;
646  RailGraphics->ChangeAllTransparentColours(Utilities->clTransparent, clB5G5R5); // original colour is as loaded at this stage - white
648 
649  TextBox->Color = clB3G3R3;
650  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
651  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
652 
653  if((Screen->Width < 1024) || (Screen->Height < 768))
654  {
655  ShowMessage("Please note that this program works best with a screen resolution of at least 1024 x 768. Please change if possible");
656  }
657  SkipFormResizeEvent = true; // added at v2.1.0
658  MasterClock->Enabled = true;
659  Visible = true; // make Interface form visible (set to false at design time) autocalls FormResize so it is skipped
660  WindowState = wsMaximized; // need this for full screen at start autocalls FormResize so it is skipped
661  MTBFEditBox->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30; // new v2.4.0 30 is to place it above the positional panel
662  // has to come after Visible = true or doesn't show
663  MTBFLabel->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30 - 55; // new v2.4.0 placed above and to the left of MTBFEditBox
664  PositionalPanel->Left = MainScreen->Left + MainScreen->Width; // changed at v2.4.0
665  PositionalPanel->Top = MainScreen->Top; // changed at v2.4.0
666  PositionalPanel->Height = MainScreen->Height; // changed at v2.4.0
667  AllSetUpFlag = true;
668  MissedTicks = 0;
669  TotalTicks = 0;
670  Level1Mode = BaseMode;
671  SetLevel1Mode(131); // to reset background colour mode menu choices
672  Screen->Cursor = TCursor(-2); // Arrow
673  SkipFormResizeEvent = false; // added at v2.1.0
674  SelectedGraphicFileName = ""; // only set to null here so always has a value after use LoadUserGraphic
675 
676  FloatingPanel->Color = TColor(0xF0FFFF); // new v2.2.0, corrects floating panel background colour in Windows 10
677  PerformancePanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
678  OperatorActionPanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
679  DevelopmentPanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
680  TTStartTimeBox->Color = TColor(0x99FFFF); // cream
681  HighlightPanel->Color = TColor(0x33CCFF);
683  MTBFEditBox->Visible = false; // new at v2.4.0
684  MTBFLabel->Visible = false;
688  CancelSelectionFlag = false;
689  TTStartTimePtr = 0;
690  TTFirstServicePtr = 0;
691  TTLastServicePtr = 0;
692  Track->OverrideAndHideSignalBridgeMessage = false; // added at v2.5.1 to allow facing signals before bridges - with a warning
693  ConflictPanel->Visible = false;
694  TTClockAdjustWarningPanel->Visible = false;
695  TTClockAdjustWarningHide = false;
696  TwoLocationNamePanel->Visible = false;
697  TwoLocationNamePanelHide = false;
698  LastNonCtrlOrShiftKeyDown = -1; // set to no key
699  ClipboardChecked = false;
700  MMoveTrackSelFlag = false;
701  MMovePrefDirSelFlag = false;
702  MMoveCopyCutSelPickedUpFlag = false;
703  MMoveTextGraphicTextFoundFlag = false;
704  MMoveTextGraphicUserGraphicFoundFlag = false;
705 
706  SigImagePanel->Left = (Interface->Width - SigImagePanel->Width) / 2; // added for v2.3.0
707 
708  // below added at v2.4.0 so able to load session files with the correct decimal point
709  Utilities->DecimalPoint = '.'; // default case is full stop
710  char *LocalNumericInformation = setlocale(LC_NUMERIC, ""); // need this to set lconv to the environment's numeric format
712  if(LocalNumericInformation == "") // call failed, don't change decimal point in Utilities.cpp
713  {
714  Utilities->SetLocaleResultOK = false;
715  }
716  struct lconv Locale; // store this structure in memory (accessed via locale.h in Utilities.h)
717  struct lconv *conv = &Locale;
718  // read the locality conversion structure
719  conv = localeconv(); // this is what updates the structure
720  Utilities->DecimalPoint = conv->decimal_point[0];
721  }
722 
723  catch(const EFOpenError &e)
724  {
725  TMsgDlgButtons But;
726  But << mbOK;
727  MessageDlg(e.Message + " - program must terminate", mtError, But, 0);
728  Application->Terminate();
729  }
730 
731  catch(const Exception &e)
732  {
733  TMsgDlgButtons But;
734  But << mbOK;
735  AnsiString Message = "A fatal error occurred during the program setup process, the program must terminate. Message = " + e.Message;
736  MessageDlg(Message, mtError, But, 0); // this message given first in case can't create the error log
737  ErrorLog(115, e.Message);
738  Application->Terminate();
739  }
740 }
741 
742 // ---------------------------------------------------------------------------
743 
744 __fastcall TInterface::~TInterface()
745 {
746  // destructor
747  try
748  {
749  // rewrite ConfigFile with signal handedness, background colour & InitialDir values (may be same but no matter)
750  AnsiString ColourStr = "", SignalStr = "";
751  remove((CurDir + "\\Config.txt").c_str());
752  std::ofstream ConfigFile((CurDir + "\\Config.txt").c_str());
753  ColourStr = "black";
754  SignalStr = "left";
755  if(Utilities->clTransparent == TColor(0xFFFFFF))
756  {
757  ColourStr = "white";
758  }
759  else if(Utilities->clTransparent == TColor(0x330000))
760  {
761  ColourStr = "blue";
762  }
764  {
765  SignalStr = "right";
766  }
767  ConfigFile << AnsiString("Signals=") << SignalStr << '\n';
768  ConfigFile << AnsiString("BgndCol=") << ColourStr << '\n';
769  ConfigFile << AnsiString("RLYLocn=") << AnsiString(LoadRailwayDialog->InitialDir) << '\n';
770  ConfigFile << AnsiString("TTBLocn=") << AnsiString(TimetableDialog->InitialDir) << '\n';
771  ConfigFile << AnsiString("SSNLocn=") << AnsiString(LoadSessionDialog->InitialDir) << '\n';
772  ConfigFile.close();
773 
774  SkipFormResizeEvent = true; // added at v2.1.0
775  delete NonSigRouteStartMarker;
776  delete SigRouteStartMarker;
777  delete AutoRouteStartMarker;
778  delete PointFlash;
779  delete SelectBitmap;
780  delete TrainController;
781  delete EveryPrefDir;
782  delete SelectPrefDir;
783  delete ConstructRoute;
784  delete ConstructPrefDir;
785  delete AllRoutes;
786  delete Track;
787  delete TextHandler;
788  delete HiddenDisplay;
789  delete HiddenScreen;
790  delete Display;
791  delete RailGraphics;
792  delete Utilities;
793  delete session_api_; //added at v2.10.0
794  DeleteFile(TempTTFileName); // added at v2.5.0 to prevent temporary files building up
795  }
796  catch(const Exception &e)
797  {
798  ErrorLog(116, e.Message);
799  }
800 }
802 
803 // ---------------------------------------------------------------------------
804 
805 void __fastcall TInterface::FormCreate(TObject *Sender)
806 {
807  // these functions have to be defined here to take effect when application activated & deactivated
808  try
809  {
810  Application->OnDeactivate = AppDeactivate;
811  Application->OnActivate = AppActivate;
812  }
813  catch(const Exception &e)
814  {
815  ErrorLog(117, e.Message);
816  }
817 }
818 
819 // ---------------------------------------------------------------------------
820 
821 void __fastcall TInterface::AppDeactivate(TObject *Sender)
822 {
823  // pause operation if operating & stop the master clock
824  try
825  {
827  {
828  if(Track->RouteFlashFlag) // in case route building - cancels the route, freezes otherwise - reported
829  {
830  // by Matt Blades 30/06/11
834  Screen->Cursor = TCursor(-2); // Arrow
835  Track->RouteFlashFlag = false;
836  ClearandRebuildRailway(48); // to get rid of displayed route
837  }
838  if(Track->PointFlashFlag)
839  // added at v1.3.1 to prevent lockup for flashing points when deactivates. Notified by Ian Walker in his email of 25/03/13.
840  {
842  Track->PointFlashFlag = false;
844  Screen->Cursor = TCursor(-2); // Arrow
845  }
846  Level2OperMode = Paused; //disable to stop pause
847  SetLevel2OperMode(2); //disable to stop pause
848  }
849  MasterClock->Enabled = false; //disable to stop pause
850  ClipboardChecked = false; // added at v2.8.0 to force a check of the clipboard (via ClockTimer2 & SetTrackModeMenu)
851  }
852  catch(const Exception &e)
853  {
854  ErrorLog(118, e.Message);
855  }
856 }
857 
858 // ---------------------------------------------------------------------------
859 
860 void __fastcall TInterface::AppActivate(TObject *Sender)
861 {
862  // restart the master clock providing Interface constructor has run
863  try
864  {
865  if(AllSetUpFlag)
866  {
867  MasterClock->Enabled = true;
868  ClipboardChecked = false; // at v2.9.0 added here too as for some unknown reason it doesn't always work when just in deactivate
869  }
870  }
871  catch(const Exception &e)
872  {
873  ErrorLog(119, e.Message);
874  }
875 }
876 
877 // ---------------------------------------------------------------------------
878 
879 UnicodeString TInterface::GetVersion()
880 {
881  DWORD VersionHandle;
882  DWORD VersionSize;
883  LPBYTE pBuffer;
884  UnicodeString strVersion = L"N/A";
885 
886  VersionSize = GetFileVersionInfoSizeW(Application->ExeName.c_str(), &VersionHandle);
887  if(VersionSize)
888  {
889  pBuffer = new BYTE[VersionSize];
890 
891  if(GetFileVersionInfoW(Application->ExeName.c_str(), VersionHandle, VersionSize, pBuffer))
892  {
893  VS_FIXEDFILEINFO *fi;
894  UINT buflen;
895 
896  // uncomment strVersion and HIWORD alternates below when future CI implemented: sas@2.1.0
897  if(VerQueryValueW(pBuffer, L"\\", (void**)&fi, &buflen))
898  {
899  // strVersion.sprintf(L"%d.%d.%d (Build %d)",
900  strVersion.sprintf(L"%d.%d.%d", HIWORD(fi->dwFileVersionMS), LOWORD(fi->dwFileVersionMS), HIWORD(fi->dwFileVersionLS));
901  // HIWORD(fi->dwFileVersionLS), LOWORD(fi->dwFileVersionLS)
902  }
903  }
904  delete[] pBuffer;
905  }
906  return(L" v" + strVersion);
907 }
908 
909 // ---------------------------------------------------------------------------
910 // Track Build Interface
911 // ---------------------------------------------------------------------------
912 void __fastcall TInterface::BuildTrackMenuItemClick(TObject *Sender) // Mode Menu Item
913 {
914  try
915  {
916  TrainController->LogEvent("BuildTrackMenuItemClick");
917  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BuildTrackMenuItemClick");
919  SetLevel1Mode(0);
920  Utilities->CallLogPop(1159);
921  }
922  catch(const Exception &e)
923  {
924  ErrorLog(120, e.Message);
925  }
926 }
927 // ---------------------------------------------------------------------------
928 
929 void __fastcall TInterface::AddTrackButtonClick(TObject *Sender)
930 {
931  try
932  {
933  TrainController->LogEvent("AddTrackButtonClick");
934  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddTrackButtonClick");
936  SetLevel1Mode(38);
939  Utilities->CallLogPop(1162);
940  }
941  catch(const Exception &e)
942  {
943  ErrorLog(121, e.Message);
944  }
945 }
946 
947 // ---------------------------------------------------------------------------
948 void __fastcall TInterface::SpeedButtonClick(TObject *Sender)
949 {
950  try
951  {
952  TrainController->LogEvent("SpeedButtonClick");
953  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedButtonClick");
954  ReselectMenuItem->Enabled = false;
955  if(((TSpeedButton*)Sender)->Down)
956  {
957  CurrentSpeedButton = (TSpeedButton*)Sender;
958 // TrainController->LogEvent("SpeedButtonClick, " + CurrentSpeedButton->Tag); //v 1.3.1 - using non-AnsiString CurrentSpeedButton->Tag sends (for an unknown reason) a completely wrong string to LogEvent, usually "...(behind this message)"
959  TrainController->LogEvent("SpeedButtonClick, " + AnsiString(CurrentSpeedButton->Tag)); // new version //use for v1.3.2
960  if((Level2TrackMode == TrackSelecting) && (CurrentSpeedButton->Tag != 144))
961  // new addition at v2.6.0 to fill selected area with the element corresponding to CurrentSpeedButton
962  {
963  // 144 = level crossing & these not permitted
964  if((SelectRect.left != SelectRect.right) && (SelectRect.top != SelectRect.bottom) && SelectionValid)
965  {
966  Screen->Cursor = TCursor(-11); // Hourglass;
967  InfoPanel->Caption = "SELECTING: Filling area with chosen element";
968  bool FillSelectionFlag = false;
970  {
971  UnicodeString MessageStr =
972  "Click 'Yes' to fill the area with the chosen element or 'No' to abort.\n" "Existing elements won't be overwritten although track can\n"
973  "have platforms and non-station named location elements added.\n\nThis message will not be shown again.";
974  int button = Application->MessageBox(MessageStr.c_str(), L"", MB_YESNO);
975  if(button == IDYES)
976  {
977  FillSelectionFlag = true;
978  }
979  }
980  if(FillSelectionFlag || FillSelectionMessageSentFlag)
981  {
982  bool TrackLinkingRequiredFlag = true;
983  for(int HLoc = SelectRect.left; HLoc < SelectRect.right; HLoc++)
984  {
985  for(int VLoc = SelectRect.top; VLoc < SelectRect.bottom; VLoc++)
986  {
987  if((HLoc != SelectRect.right) || (VLoc != SelectRect.bottom))
988  {
989  Track->PlotAndAddTrackElement(3, CurrentSpeedButton->Tag, 0, HLoc, VLoc, TrackLinkingRequiredFlag, false);
990 // false for internal checks
991  // above now has extra zero 'Aspect' parameter at v2.2.0 so can distinguish between adding track and pasting
992  }
993  else
994  {
995  Track->PlotAndAddTrackElement(4, CurrentSpeedButton->Tag, 0, HLoc, VLoc, TrackLinkingRequiredFlag, true);
996 // internal checks true for last plot
997  }
998  }
999  }
1000  }
1001  Track->SetTrackFinished(false);
1002  ClearandRebuildRailway(80); // to remove selection outline
1003  SelectionValid = false;
1004  Track->CopyFlag = false;
1006  ResetSelectRect();
1007  SetLevel1Mode(139);
1009  SetLevel2TrackMode(66);
1011  Screen->Cursor = TCursor(-2); // Arrow
1012  ReselectMenuItem->Enabled = true; // allow when filling areas
1013  }
1014  }
1015  }
1016  else
1017  {
1018  CurrentSpeedButton = 0;
1019  }
1020  Utilities->CallLogPop(1163);
1021  }
1022  catch(const Exception &e)
1023  {
1024  ErrorLog(122, e.Message);
1025  }
1026 }
1027 
1028 // ---------------------------------------------------------------------------
1029 void __fastcall TInterface::TrackOKButtonClick(TObject *Sender)
1030 {
1031  try
1032  {
1033  TrainController->LogEvent("TrackOKButtonClick");
1034  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrackOKButtonClick");
1035  SelectionValid = false;
1037  bool LocError;
1038  int HLoc, VLoc;
1039  // erase any corrupted PrefDirs then rebuild track & PrefDir vectors
1040 // EveryPrefDir->EraseCorruptedElementsAfterTrackBuild(); not needed after dispensed with blank track elements for erased elements
1041  if(!(Track->TryToConnectTrack(0, LocError, HLoc, VLoc, true))) // true for give messages
1042  // if successful repositions TrackVector & builds TrackMap
1043  {
1044  if(LocError) // links not complete or other error - show offending element
1045  {
1046  while((Display->DisplayOffsetH - HLoc) > 0)
1047  {
1048  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
1049  }
1050  while((HLoc - Display->DisplayOffsetH) > (Utilities->ScreenElementWidth - 1))
1051  {
1053  }
1054  while((Display->DisplayOffsetV - VLoc) > 0)
1055  {
1056  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
1057  }
1058  while((VLoc - Display->DisplayOffsetV) > (Utilities->ScreenElementHeight - 1))
1059  {
1061  }
1063  Display->InvertElement(0, HLoc * 16, VLoc * 16);
1064  ShowMessage("Incomplete track or other error - see inverted element (may be behind this message)");
1065  ClearandRebuildRailway(1); // to clear inversion
1067  SetLevel1Mode(39);
1068  Level2TrackMode = AddTrack; // go to add track regardless of where started from
1069  SetLevel2TrackMode(3);
1070  Utilities->CallLogPop(0);
1071  return;
1072  }
1073  else
1074  {
1075  // reach here if there are no track elements
1076  ShowMessage("Unable to set any track links");
1078  SetLevel1Mode(40);
1080  SetLevel2TrackMode(4); // go to add track regardless of where started from
1081  Utilities->CallLogPop(1);
1082  return;
1083  }
1084  }
1085  else
1086  {
1087  // success so far as track is concerned ('TrackFinished' set in TryToConnectTrack)
1088  EveryPrefDir->RebuildPrefDirVector(0); // from TrackMap
1089  }
1090 // success if reach here ('TrackFinished' set in TryToConnectTrack)
1091  if(Level2TrackMode == AddTrack)
1092  {
1095  SetLevel1Mode(41);
1096  SetLevel2TrackMode(5);
1097  }
1098  else
1099  {
1101  SetLevel1Mode(36); // back to TrackMode if not in AddTrack mode
1102  }
1103  ShowMessage("Successful Completion");
1104  Utilities->CallLogPop(2);
1105  }
1106  catch(const Exception &e)
1107  {
1108  ErrorLog(3, e.Message);
1109  }
1110 }
1111 
1112 // ---------------------------------------------------------------------------
1113 void __fastcall TInterface::SetGapsButtonClick(TObject *Sender)
1114 {
1115  try
1116  {
1117  TrainController->LogEvent("SetGapsButtonClick");
1118  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SetGapsButtonClick");
1119  SelectionValid = false;
1120  ReselectMenuItem->Enabled = false;
1122  SetLevel1Mode(42);
1124  SetLevel2TrackMode(6);
1125  Utilities->CallLogPop(1164);
1126  }
1127  catch(const Exception &e)
1128  {
1129  ErrorLog(123, e.Message);
1130  }
1131 }
1132 
1133 // ---------------------------------------------------------------------------
1134 void __fastcall TInterface::AddTextButtonClick(TObject *Sender)
1135 {
1136  try
1137  {
1138  TrainController->LogEvent("AddTextButtonClick");
1139  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddTextButtonClick");
1141  SetLevel1Mode(43);
1143  SetLevel2TrackMode(7);
1144  Utilities->CallLogPop(1165);
1145  }
1146  catch(const Exception &e)
1147  {
1148  ErrorLog(124, e.Message);
1149  }
1150 }
1151 
1152 // ---------------------------------------------------------------------------
1153 void __fastcall TInterface::MoveTextOrGraphicButtonClick(TObject *Sender)
1154 {
1155  try
1156  {
1157  TrainController->LogEvent("MoveTextOrGraphicButtonClick");
1158  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTextOrGraphicButtonClick");
1160  SetLevel1Mode(44);
1162  SetLevel2TrackMode(8);
1163  Utilities->CallLogPop(1166);
1164  }
1165  catch(const Exception &e)
1166  {
1167  ErrorLog(125, e.Message);
1168  }
1169 }
1170 
1171 // ---------------------------------------------------------------------------
1172 void __fastcall TInterface::TextBoxKeyPress(TObject *Sender, char &Key)
1173 {
1174  try
1175  {
1176  TrainController->LogEvent("TextBoxKeyPress," + AnsiString(Key));
1177  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TextBoxKeyPress," + AnsiString(Key));
1178  if(Key == '\x0D') // CR
1179  {
1180  if(TextBox->Text != "") // if blank then don't save
1181  {
1182  if(Display->GetFont()->Color == clB5G5R5) // white
1183  {
1184  TFont *TempFont = new TFont;
1185  TempFont->Assign(Display->GetFont());
1186  TempFont->Color = clB0G0R0; // change to black for vector & saving
1187  Display->SetFont(TempFont);
1188  delete TempFont;
1189  }
1190  TFont *DisplayFont = Display->GetFont();
1191  TTextItem TempText = TTextItem(Text_X, Text_Y, TextBox->Text, DisplayFont);
1192  TempText.Font = DisplayFont; // may have been changed in above constructor when returned as reference
1194  ResetChangedFileDataAndCaption(12, true); // moved here from MainScreenMouseDown2 after 2.7.0 in case nothing changed
1195  }
1196  EditMenu->Enabled = true;
1197  TextBox->Visible = false;
1198  SetLevel2TrackMode(56); // to enable 'move text' if first text item added
1199  }
1200  else if(Key == '\x1B') // escape
1201  {
1202  if(TextBox->Text != "")
1203  {
1204  ResetChangedFileDataAndCaption(28, true); // added here after 2.7.0 in case replaced existing text (which is selected) with blank
1205  }
1206  TextBox->Visible = false;
1207  }
1208  Utilities->CallLogPop(3);
1209  }
1210  catch(const Exception &e)
1211  {
1212  ErrorLog(4, e.Message);
1213  }
1214 }
1215 
1216 // ---------------------------------------------------------------------------
1217 void __fastcall TInterface::LocationNameButtonClick(TObject *Sender)
1218 {
1219  try
1220  {
1221  TrainController->LogEvent("LocationNameButtonClick");
1222  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameButtonClick");
1224  SetLevel1Mode(45);
1226  SetLevel2TrackMode(9);
1227  Utilities->CallLogPop(1167);
1228  }
1229  catch(const Exception &e)
1230  {
1231  ErrorLog(126, e.Message);
1232  }
1233 }
1234 
1235 // ---------------------------------------------------------------------------
1236 void __fastcall TInterface::LocationNameKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
1237 {
1238  try
1239  {
1240  TrainController->LogEvent("LocationNameKeyUp," + AnsiString(Key));
1241  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameKeyUp," + AnsiString(Key));
1242  if(Track->LNPendingList.empty())
1243  {
1244  ShowMessage("Error, location name being entered without an entry in LNPendingList");
1246  SetLevel1Mode(46);
1248  SetLevel2TrackMode(10);
1249  Utilities->CallLogPop(4);
1250  return;
1251  }
1252  if(Key == '\x1B') // escape
1253  {
1254  Track->LNPendingList.clear(); // get rid of existing entry
1256  SetLevel1Mode(47);
1258  SetLevel2TrackMode(11);
1259  Utilities->CallLogPop(5);
1260  return;
1261  }
1262  if(Key == '\x0D')
1263  {
1264  Screen->Cursor = TCursor(-11); // Hourglass;
1266  ResetChangedFileDataAndCaption(8, true); // moved here after 2.7.0 from mainScreenMouseDown2 in case nothing changed
1267  AnsiString ExistingName;
1268  LocationNameTextBox->Text = LocationNameTextBox->Text.Trim();
1269 // added at v2.6.1 to prevent added spaces because they skip the different location same name chack
1270  if(Track->LNPendingList.front() > -1)
1271  {
1272  ExistingName = Track->InactiveTrackElementAt(27, Track->LNPendingList.front()).LocationName;
1273  }
1274  else
1275  {
1276  ExistingName = Track->TrackElementAt(425, -1 - (Track->LNPendingList.front())).LocationName;
1277  }
1278  if(Track->LocationNameAllocated(1, LocationNameTextBox->Text) && (ExistingName != LocationNameTextBox->Text))
1279  {
1280  // name allocated to a different location
1281  UnicodeString MessageStr = UnicodeString("Another location named '") + LocationNameTextBox->Text +
1282  UnicodeString("' already exists. If you continue its name will be erased. Do you wish to continue?");
1283  int button = Application->MessageBox(MessageStr.c_str(), L"Warning!", MB_YESNO | MB_ICONWARNING);
1284  if(button == IDNO)
1285  {
1286  Track->LNPendingList.clear(); // get rid of existing entry
1287  Screen->Cursor = TCursor(-2); // Arrow
1289  SetLevel1Mode(48);
1291  SetLevel2TrackMode(12);
1292  Utilities->CallLogPop(6);
1293  return;
1294  }
1296  Track->EnterLocationName(1, LocationNameTextBox->Text, false);
1297  int HPos, VPos;
1298  bool UseExistingPosition = false;
1299  if(EraseLocationNameText(0, LocationNameTextBox->Text, HPos, VPos))
1300  {
1301  ;
1302  } // condition not used
1303 
1304  // above may be redundant at v1.1.0 due to name erase in EnterLocationName
1305  // but, the location to be named may also have an existing name, in which case that needs to be erased
1306  // and the position re-used
1307  if(ExistingName != "")
1308  {
1309  if(EraseLocationNameText(3, ExistingName, HPos, VPos))
1310  {
1311  UseExistingPosition = true; // may be redundant at v1.1.0 due to name erase in EnterLocationName
1312  }
1313  }
1314  AddLocationNameText(0, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1315  Screen->Cursor = TCursor(-2); // Arrow
1317  SetLevel1Mode(49);
1319  SetLevel2TrackMode(13);
1320  Utilities->CallLogPop(7);
1321  return;
1322  }
1323  else if(Track->LocationNameAllocated(2, LocationNameTextBox->Text) && (ExistingName == LocationNameTextBox->Text))
1324  {
1325  // same name being entered again
1326  Track->LNPendingList.clear(); // get rid of existing entry as the location already has this name
1327  // but in case the name is not already in text vector erase it and re-add it
1328  // if it wasn't in the vector erasing it has no effect
1329  int HPos, VPos;
1330  bool UseExistingPosition = false;
1331  if(EraseLocationNameText(2, LocationNameTextBox->Text, HPos, VPos))
1332  {
1333  UseExistingPosition = true;
1334  }
1335  // above may be redundant at v1.1.0 due to name erase in EnterLocationName
1336  AddLocationNameText(2, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1337  Screen->Cursor = TCursor(-2); // Arrow
1339  SetLevel1Mode(50);
1341  SetLevel2TrackMode(14);
1342  Utilities->CallLogPop(8);
1343  return;
1344  }
1345  else
1346  {
1347  // either a new name for an unnamed location, or a different name for a named location
1348  // check validity of entry
1349  AnsiString LocStr = LocationNameTextBox->Text;
1350  LocStr = LocStr.Trim(); // strip leading & trailing spaces, and control characters
1351  LocationNameTextBox->Text = LocStr; // reset this as used below
1352 /* drop this, now covered by ...Trim() above
1353  //strip leading spaces
1354  while((LocStr != "") && (LocStr[1] == ' '))
1355  {
1356  LocStr = LocStr.SubString(2, LocStr.Length()-1);
1357  }
1358 */
1359  if((LocStr != "") && (LocStr[1] >= '0') && (LocStr[1] <= '9')) // can't begin with a number
1360  {
1361  Screen->Cursor = TCursor(-2); // Arrow
1362  ShowMessage("Location name can't begin with a number");
1364  SetLevel1Mode(51);
1366  SetLevel2TrackMode(15);
1367  Utilities->CallLogPop(776);
1368  return;
1369  }
1370  if(LocStr.Length() > 50)
1371  {
1372  Screen->Cursor = TCursor(-2); // Arrow
1373  ShowMessage("Location name too long, 50 characters maximum");
1375  SetLevel1Mode(122);
1377  SetLevel2TrackMode(55);
1378  Utilities->CallLogPop(1735);
1379  return;
1380  }
1381  for(int x = 1; x <= LocStr.Length(); x++)
1382  {
1383  char Ch = LocStr[x];
1384  if((Ch != ' ') && (Ch != '&') && (Ch != '(') && (Ch != ')') && (Ch != ':') && (Ch != 39) && (Ch != '.') && (Ch != '-') && (Ch != '+') &&
1385  (Ch != '/') && ((Ch < '0') || (Ch > '9')) && ((Ch < 'A') || (Ch > 'Z')) && ((Ch < 'a') || (Ch > 'z')))
1386  {
1387  Screen->Cursor = TCursor(-2); // Arrow
1388  ShowMessage(
1389  "Location name contains one or more invalid characters, must be alphanumeric, brackets, space, full stop, colon, inverted comma, '-', '+', '/' or '&&'");
1391  SetLevel1Mode(52);
1393  SetLevel2TrackMode(16);
1394  Utilities->CallLogPop(777);
1395  return;
1396  }
1397  }
1398  if(LocStr == "cdt") // this has Time:Command which could be confused with Time:Loc
1399  {
1400  Screen->Cursor = TCursor(-2); // Arrow
1401  ShowMessage("Location name cannot be 'cdt', this name would interfere with the timetable");
1403  SetLevel1Mode(53);
1405  SetLevel2TrackMode(17);
1406  Utilities->CallLogPop(778);
1407  return;
1408  }
1409  Track->EnterLocationName(2, LocStr, false);
1410  // need to check if the location already has a name, and if so erase it from the textvector
1411  int HPos, VPos;
1412  bool UseExistingPosition = false;
1413  if(ExistingName != "")
1414  {
1415  if(EraseLocationNameText(1, ExistingName, HPos, VPos))
1416  {
1417  UseExistingPosition = true; // may be redundant at v1.1.0 due to name erase in EnterLocationName
1418  }
1419  }
1420  AddLocationNameText(1, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1421  Screen->Cursor = TCursor(-2); // Arrow
1423  SetLevel1Mode(54);
1425  SetLevel2TrackMode(18);
1426  Utilities->CallLogPop(9);
1427  return;
1428  }
1429  }
1430  Screen->Cursor = TCursor(-2); // Arrow
1431  Utilities->CallLogPop(10);
1432  }
1433  catch(const Exception &e)
1434  {
1435  ErrorLog(5, e.Message);
1436  }
1437 }
1438 
1439 // ---------------------------------------------------------------------------
1440 void __fastcall TInterface::SetLengthsButtonClick(TObject *Sender)
1441 {
1442  try
1443  {
1444  TrainController->LogEvent("SetLengthsButtonClick");
1445  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SetLengthsButtonClick");
1446  SelectLengthsFlag = false;
1447  ConstructPrefDir->ExternalClearPrefDirAnd4MultiMap(); // added for extended distances
1449  SetLevel1Mode(55);
1451  SetLevel2TrackMode(19);
1452  Utilities->CallLogPop(1168);
1453  }
1454  catch(const Exception &e)
1455  {
1456  ErrorLog(127, e.Message);
1457  }
1458 }
1459 
1460 // ---------------------------------------------------------------------------
1461 void __fastcall TInterface::LengthOKButtonClick(TObject *Sender)
1462 {
1463  try
1464  {
1465  TrainController->LogEvent("LengthOKButtonClick," + DistanceBox->Text + "," + SpeedLimitBox->Text);
1466  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthOKButtonClick");
1467  ResetChangedFileDataAndCaption(4, true); // moved here after 2.7.0 so only need to save if something changed
1468  int Dist = 0, SpeedLimit = 0;
1469  AnsiString DistanceStr = DistanceBox->Text;
1470  if(SelectLengthsFlag && (DistanceStr == ""))
1471  {
1472  DistanceStr = "No change";
1473  }
1474  AnsiString SpeedStr = SpeedLimitBox->Text;
1475  if(SelectLengthsFlag && (SpeedStr == ""))
1476  {
1477  SpeedStr = "No change";
1478  }
1479  if(SelectLengthsFlag)
1480  {
1481  if(DistanceStr == "No change")
1482  {
1483  Dist = -1; // i.e.don't change
1484  }
1485  if(SpeedStr == "No change")
1486  {
1487  SpeedLimit = -1; // i.e.don't change
1488  }
1489  }
1490  else
1491  {
1492  if(DistanceStr == AnsiString(OverallDistance))
1493  {
1494  Dist = -1; // i.e.don't change
1495  }
1496  if((SpeedStr == "Mixed") || (SpeedStr == AnsiString(OverallSpeedLimit)))
1497  {
1498  SpeedLimit = -1; // i.e.don't change
1499  }
1500  }
1501  if(((Dist != -1) && (DistanceStr.Length() > 6)) || ((SpeedLimit != -1) && (SpeedStr.Length() > 6)))
1502  {
1503  ShowMessage("One or more entries too long");
1504  Utilities->CallLogPop(11);
1505  return;
1506  }
1507  if((DistanceStr == "") || (SpeedStr == ""))
1508  {
1509  ShowMessage("One or more entries blank");
1510  Utilities->CallLogPop(12);
1511  return;
1512  }
1513  if(SelectLengthsFlag && (Dist != -1))
1514  {
1515  for(int x = 1; x <= DistanceStr.Length(); x++)
1516  {
1517  if((DistanceStr[x] < '0') || (DistanceStr[x] > '9'))
1518  {
1519  ShowMessage("Track length value must be a positive whole number, or blank for no change");
1520  Utilities->CallLogPop(1415);
1521  return;
1522  }
1523  }
1524  }
1525  if(!SelectLengthsFlag)
1526  {
1527  for(int x = 1; x <= DistanceStr.Length(); x++)
1528  {
1529  if((DistanceStr[x] < '0') || (DistanceStr[x] > '9'))
1530  {
1531  ShowMessage("Distance must be a positive whole number");
1532  Utilities->CallLogPop(13);
1533  return;
1534  }
1535  }
1536  }
1537  if(SelectLengthsFlag && (SpeedLimit != -1))
1538  {
1539  for(int x = 1; x <= SpeedStr.Length(); x++)
1540  {
1541  if((SpeedStr[x] < '0') || (SpeedStr[x] > '9'))
1542  {
1543  ShowMessage("Speed limit must be a positive whole number, or blank for no change");
1544  Utilities->CallLogPop(1416);
1545  return;
1546  }
1547  }
1548  }
1549  if(!SelectLengthsFlag && (SpeedStr != "Mixed"))
1550  {
1551  for(int x = 1; x <= SpeedStr.Length(); x++)
1552  {
1553  if((SpeedStr[x] < '0') || (SpeedStr[x] > '9'))
1554  {
1555  ShowMessage("Speed limit must be a positive whole number, or 'Mixed'");
1556  Utilities->CallLogPop(14);
1557  return;
1558  }
1559  }
1560  }
1561  if(Dist != -1)
1562  {
1563  Dist = DistanceStr.ToInt();
1564  }
1565  if(SpeedLimit != -1)
1566  {
1567  SpeedLimit = SpeedStr.ToInt();
1568  }
1569 /* don't need this with new condition below
1570  if(SelectLengthsFlag && (Dist != -1) && (Dist < 20))
1571  {
1572  ShowMessage("Track length value must be a minimum of 20m, setting to 20m");
1573  Dist = 20;
1574  }
1575 */
1576  if(((Dist != -1) && (Dist < 20)) || ((SpeedLimit != -1) && (SpeedLimit < 10)) || ((SpeedLimit != -1) && (SpeedLimit > TTrain::MaximumSpeedLimit)))
1577  // new limiting values for v0.6 (used only to fail at either value 0); added TTrain::MaxSpeedLimit at v2.1.0
1578  {
1579  ShowMessage("Lengths must be 20m or more, and speeds must be between 10km/h and 400km/h"); // changed at v2.1.0 to limit max speed
1580  Utilities->CallLogPop(15);
1581  return;
1582  }
1583  DistanceBox->Text = "";
1584  SpeedLimitBox->Text = "";
1585  if(SelectLengthsFlag)
1586  {
1587  int LowSelectHLoc = SelectBitmapHLoc;
1588  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
1589  int LowSelectVLoc = SelectBitmapVLoc;
1590  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
1591  bool FoundFlag;
1592  bool NamedLocPresent = false;
1593  if((Dist != -1) && (Dist != DefaultTrackLength))
1594  {
1595  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1596  {
1597  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1598  {
1600  {
1601  NamedLocPresent = true;
1602  }
1603  }
1604  }
1605  }
1606  if(NamedLocPresent && (Dist < 50)) // changed in v2.4.0
1607  {
1608  if(!TooShortMessageSentFlag) //added at v2.9.1
1609  {
1610  ShowMessage("Note: Named location elements are quite short. If they are too short the simulation might be too unrealistic.\n\nThis message will not be shown again.");
1611  TooShortMessageSentFlag = true; //added at v2.9.1
1612  }
1613  }
1614  if(NamedLocPresent && (Dist > 200)) // changed in v2.4.0
1615  {
1616  if(!TooLongMessageSentFlag) //added at v2.9.1
1617  {
1618  ShowMessage("Note: Named location elements are quite long. If they are too long the simulation might be too unrealistic.\n\nThis message will not be shown again.");
1619  TooLongMessageSentFlag = true; //added at v2.9.1
1620  }
1621  }
1622  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1623  {
1624  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1625  {
1626  int VecPos = Track->GetVectorPositionFromTrackMap(34, x, y, FoundFlag);
1627  if(FoundFlag)
1628  {
1629  if(Dist > -1) // && !(Track->IsPlatformOrNamedNonStationLocationPresent(7, x, y)))
1630  {
1631  Track->TrackElementAt(692, VecPos).Length01 = Dist;
1632  if(Track->TrackElementAt(693, VecPos).Length23 != -1)
1633  {
1634  Track->TrackElementAt(694, VecPos).Length23 = Dist;
1635  }
1636  }
1637  if(SpeedLimit > -1)
1638  {
1639  Track->TrackElementAt(695, VecPos).SpeedLimit01 = SpeedLimit;
1640  if(Track->TrackElementAt(696, VecPos).SpeedLimit23 != -1)
1641  {
1642  Track->TrackElementAt(697, VecPos).SpeedLimit23 = SpeedLimit;
1643  }
1644  }
1645  }
1646  }
1647  }
1648  TrackLengthPanel->Visible = false;
1649  SelectLengthsFlag = false; // go back to normal distance setting mode
1650  }
1651  else
1652  {
1653  SetTrackLengths(1, Dist, SpeedLimit);
1654  }
1656  SetLevel1Mode(57);
1658  SetLevel2TrackMode(21);
1659  Utilities->CallLogPop(16);
1660  }
1661  catch(const Exception &e)
1662  {
1663  ErrorLog(6, e.Message);
1664  }
1665 }
1666 
1667 // ---------------------------------------------------------------------------
1668 void __fastcall TInterface::LengthCancelButtonClick(TObject * Sender)
1669 {
1670  try
1671  {
1672  TrainController->LogEvent("LengthCancelButtonClick");
1673  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthCancelButtonClick");
1674  DistanceBox->Text = "";
1675  SpeedLimitBox->Text = "";
1676  TrackLengthPanel->Visible = false;
1677  SelectLengthsFlag = false; // go back to normal distance setting mode
1679  SetLevel1Mode(59);
1681  SetLevel2TrackMode(23);
1682  Utilities->CallLogPop(1169);
1683  }
1684  catch(const Exception &e)
1685  {
1686  ErrorLog(128, e.Message);
1687  }
1688 }
1689 
1690 // ---------------------------------------------------------------------------
1691 void __fastcall TInterface::ResetDefaultLengthButtonClick(TObject *Sender)
1692 {
1693  try
1694  {
1695  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ResetDefaultLengthButtonClick");
1696  TMsgDlgButtons Buttons;
1697  Buttons << mbYes << mbNo;
1698  if(MessageDlg("This will reset the selected elements to default lengths & speed limits. Proceed?", mtWarning, Buttons, 0) == mrNo)
1699  {
1700  // leave all as was before
1701  Utilities->CallLogPop(17);
1702  return;
1703  }
1704  else
1705  {
1706  TrainController->LogEvent("Accepted ResetDefaultLengthButtonClick");
1707  ResetChangedFileDataAndCaption(25, true); // added after 2.7.0 so only need to save if something changed
1708  DistanceBox->Text = "";
1709  SpeedLimitBox->Text = "";
1710  if(SelectLengthsFlag)
1711  {
1712  int LowSelectHLoc = SelectBitmapHLoc;
1713  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
1714  int LowSelectVLoc = SelectBitmapVLoc;
1715  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
1716  bool FoundFlag;
1717  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1718  {
1719  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1720  {
1721  int VecPos = Track->GetVectorPositionFromTrackMap(35, x, y, FoundFlag);
1722  if(FoundFlag)
1723  {
1725  if(Track->TrackElementAt(699, VecPos).Length23 != -1)
1726  {
1728  }
1730  if(Track->TrackElementAt(702, VecPos).SpeedLimit23 != -1)
1731  {
1733  }
1734  }
1735  }
1736  }
1737  TrackLengthPanel->Visible = false;
1738 // ClearandRebuildRailway(47); don't need this
1739  SelectLengthsFlag = false; // go back to normal distance setting mode
1740  }
1741  else
1742  {
1743  TrackLengthPanel->Visible = false;
1744  bool FoundFlag;
1745  if(ConstructPrefDir->PrefDirSize() == 0)
1746  {
1747  Utilities->CallLogPop(1120);
1748  return;
1749  }
1750  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
1751  {
1752  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(169, x);
1753  TTrackElement & TrackElement = Track->TrackElementAt(37, Track->GetVectorPositionFromTrackMap(40, PrefDirElement.HLoc, PrefDirElement.VLoc,
1754  FoundFlag));
1755  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover) || (TrackElement.TrackType == Bridge))
1756  // only set the relevant track to default length & speed limit
1757  {
1758  if((PrefDirElement.GetELinkPos() < 2) && (PrefDirElement.GetXLinkPos() < 2)) // could be one of each for points
1759  {
1760  TrackElement.Length01 = DefaultTrackLength;
1761  TrackElement.SpeedLimit01 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1762  }
1763  else
1764  {
1765  TrackElement.Length23 = DefaultTrackLength;
1766  TrackElement.SpeedLimit23 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1767  }
1768  }
1769  else // any other 1 track element, including platforms being present
1770  {
1771  if((PrefDirElement.GetELinkPos() > 1) && (PrefDirElement.GetXLinkPos() > 1))
1772  {
1773  throw Exception("Error, XLinkPos > 1 in SetOneDefaultTrackLength at " + AnsiString(TrackElement.HLoc) + " & " +
1774  AnsiString(TrackElement.VLoc));
1775  }
1776  TrackElement.Length01 = DefaultTrackLength;
1777  TrackElement.SpeedLimit01 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1778  TrackElement.Length23 = -1;
1779  TrackElement.SpeedLimit23 = -1;
1780  }
1781  }
1782  }
1784  SetLevel1Mode(61);
1786  SetLevel2TrackMode(25);
1787  }
1788  Utilities->CallLogPop(18);
1789  }
1790  catch(const Exception &e)
1791  {
1792  ErrorLog(7, e.Message);
1793  }
1794 }
1795 
1796 // ---------------------------------------------------------------------------
1797 void __fastcall TInterface::RestoreAllDefaultLengthsButtonClick(TObject *Sender)
1798 {
1799  try
1800  {
1801  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RestoreAllDefaultLengthsButtonClick");
1802  TMsgDlgButtons Buttons;
1803  Buttons << mbYes << mbNo;
1804  if(MessageDlg("This will reset ALL track elements to default lengths & speed limits. Proceed?", mtWarning, Buttons, 0) == mrNo)
1805  {
1806  // leave all as was before
1807  Utilities->CallLogPop(19);
1808  return;
1809  }
1810  else
1811  {
1813  }
1814  TrainController->LogEvent("Accepted RestoreAllDefaultLengthsButtonClick");
1815  ResetChangedFileDataAndCaption(26, true); // added after 2.7.0 so only need to save if something changed
1816  DistanceBox->Text = "";
1817  SpeedLimitBox->Text = "";
1818  TrackLengthPanel->Visible = false;
1819  SelectLengthsFlag = false; // go back to normal distance setting mode
1821  SetLevel1Mode(63);
1823  SetLevel2TrackMode(27);
1824  Utilities->CallLogPop(20);
1825  }
1826  catch(const Exception &e)
1827  {
1828  ErrorLog(8, e.Message);
1829  }
1830 }
1831 
1832 // ---------------------------------------------------------------------------
1833 void __fastcall TInterface::ExitTrackButtonClick(TObject *Sender)
1834 {
1835  try
1836  {
1837  TrainController->LogEvent("ExitTrackButtonClick");
1838  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitTrackButtonClick");
1839  if(Level2TrackMode == CutMoving)
1840  {
1841  Level2TrackMode = Pasting; // to paste the selection
1842  SetLevel2TrackMode(53);
1843  }
1844  DevelopmentPanel->Visible = false; // development use only
1845  ScreenGridFlag = false;
1846  SelectionValid = false;
1847  Track->SelectGraphicVector.clear();
1848  // delete all unwanted TPictures in UserGraphicMap
1849  if(!Track->UserGraphicMap.empty()) // if empty skip it
1850  {
1851  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1852  do
1853  {
1854  bool GraphicFoundInVector = false;
1855  for(TTrack::TUserGraphicVector::iterator UGVIt = Track->UserGraphicVector.begin(); UGVIt < Track->UserGraphicVector.end(); UGVIt++)
1856  {
1857  if(UGMIt->first == UGVIt->FileName)
1858  {
1859  GraphicFoundInVector = true;
1860  break;
1861  }
1862  }
1863  if(!GraphicFoundInVector)
1864  {
1865  delete UGMIt->second;
1866  Track->UserGraphicMap.erase(UGMIt);
1867  UGMIt = Track->UserGraphicMap.begin(); // reset the iterator because erasing an element it points to invalidates it & if use it after then
1868  // behaviour is undefined, the iteration will end eventually because the map has got shorter after an erase
1869  }
1870  else
1871  {
1872  UGMIt++;
1873  }
1874  }
1875  while(UGMIt != Track->UserGraphicMap.end());
1876  }
1877  Level1Mode = BaseMode;
1878  SetLevel1Mode(2);
1879  Utilities->CallLogPop(1170);
1880  }
1881  catch(const Exception &e)
1882  {
1883  ErrorLog(129, e.Message);
1884  }
1885 }
1886 
1887 // ---------------------------------------------------------------------------
1888 void __fastcall TInterface::TextOrUserGraphicGridButtonClick(TObject *Sender)
1889 {
1890  try
1891  {
1892  TrainController->LogEvent("TextOrUserGraphicGridButtonClick," + AnsiString(TextOrUserGraphicGridVal));
1893  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TextOrUserGraphicGridButtonClick");
1894  if(TextOrUserGraphicGridVal == 1)
1895  {
1897  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision2");
1898  }
1899  else if(TextOrUserGraphicGridVal == 2)
1900  {
1902  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision4");
1903  }
1904  else if(TextOrUserGraphicGridVal == 4)
1905  {
1907  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision8");
1908  }
1909  else if(TextOrUserGraphicGridVal == 8)
1910  {
1912  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision16");
1913  }
1914  else
1915  {
1917  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
1918  }
1919  Utilities->CallLogPop(1171);
1920  }
1921  catch(const Exception &e)
1922  {
1923  ErrorLog(130, e.Message);
1924  }
1925 }
1926 
1927 // ---------------------------------------------------------------------------
1928 void __fastcall TInterface::SigAspectButtonClick(TObject *Sender)
1929 {
1930  try
1931  {
1932  TrainController->LogEvent("SigAspectButtonClick," + AnsiString(Track->SignalAspectBuildMode));
1933  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigAspectButtonClick");
1935  {
1937  SigAspectButton->Glyph->LoadFromResourceName(0, "ThreeAspect");
1938  }
1940  {
1942  SigAspectButton->Glyph->LoadFromResourceName(0, "TwoAspect");
1943  }
1945  {
1947  SigAspectButton->Glyph->LoadFromResourceName(0, "GroundSig");
1948 // set all signal glyphs to ground signals
1950  }
1951  else
1952  {
1954  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect");
1955 // set all signal glyphs to normal signals
1957  }
1958  Utilities->CallLogPop(1869);
1959  }
1960  catch(const Exception &e)
1961  {
1962  ErrorLog(180, e.Message);
1963  }
1964 }
1965 
1966 // ---------------------------------------------------------------------------
1967 void __fastcall TInterface::FontButtonClick(TObject *Sender)
1968 {
1969  try
1970  {
1971  TrainController->LogEvent("FontButtonClick");
1972  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FontButtonClick");
1973  FontDialog->Font = Display->GetFont(); // sets the dialog box font to the currently used font
1974  FontDialog->Execute(); // this displays the dialog box
1975  if(FontDialog->Font->Color == clB5G5R5) // white
1976  {
1977  FontDialog->Font->Color = clB0G0R0; // black - don't store white in font, will display black as white on dark backgrounds
1978  }
1979  Display->SetFont(FontDialog->Font); // sets the displayed font to the output from the dialog box
1980  if(TextBox->Visible)
1981  {
1982  TextBox->SetFocus();
1983  }
1984  else if(LocationNameTextBox->Visible)
1985  {
1986  LocationNameTextBox->SetFocus();
1987  }
1988  Utilities->CallLogPop(1172);
1989  }
1990  catch(const Exception &e)
1991  {
1992  ErrorLog(131, e.Message);
1993  }
1994 }
1995 
1996 // ---------------------------------------------------------------------------
1997 
1998 void __fastcall TInterface::ScreenGridButtonClick(TObject *Sender)
1999 {
2000  try
2001  {
2002  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenGridButtonClick");
2003  if(ScreenGridFlag)
2004  {
2005  TrainController->LogEvent("ScreenGridButtonClick + ScreenGrid off");
2006  ScreenGridFlag = false;
2007  }
2008  else
2009  {
2010  TrainController->LogEvent("ScreenGridButtonClick + ScreenGrid on");
2011  ScreenGridFlag = true;
2012  }
2014  Utilities->CallLogPop(89);
2015  }
2016  catch(const Exception &e)
2017  {
2018  ErrorLog(33, e.Message);
2019  }
2020 }
2021 
2022 // ---------------------------------------------------------------------------
2023 // PrefDir Interface
2024 // ---------------------------------------------------------------------------
2025 void __fastcall TInterface::PlanPrefDirsMenuItemClick(TObject *Sender) // Mode Menu Item
2026 {
2027  try
2028  {
2029  TrainController->LogEvent("PlanPrefDirsMenuItemClick");
2030  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PlanPrefDirsMenuItemClick");
2032  SetLevel1Mode(3);
2033  Utilities->CallLogPop(1173);
2034  }
2035  catch(const Exception &e)
2036  {
2037  ErrorLog(132, e.Message);
2038  }
2039 }
2040 
2041 // ---------------------------------------------------------------------------
2042 void __fastcall TInterface::AddPrefDirButtonClick(TObject *Sender)
2043 {
2044  try
2045  {
2046  TrainController->LogEvent("AddPrefDirButtonClick");
2047  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddPrefDirButtonClick");
2048  if(ConstructPrefDir->PrefDirSize() == 0)
2049  {
2050  ShowMessage("No preferred direction selection");
2051  Utilities->CallLogPop(22);
2052  return;
2053  }
2054  Screen->Cursor = TCursor(-11); // Hourglass;
2056  {
2058  }
2060  SetLevel1Mode(4);
2061  Screen->Cursor = TCursor(-2); // Arrow
2062  Utilities->CallLogPop(23);
2063  }
2064  catch(const Exception &e)
2065  {
2066  ErrorLog(10, e.Message);
2067  }
2068 }
2069 
2070 // ---------------------------------------------------------------------------
2071 void __fastcall TInterface::DeleteAllPrefDirButtonClick(TObject *Sender)
2072 {
2073  try
2074  {
2075  TrainController->LogEvent("DeleteAllPrefDirButtonClick");
2076  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteAllPrefDirButtonClick");
2077  TMsgDlgButtons Buttons;
2078  Buttons << mbYes << mbNo;
2079  if(MessageDlg("Do you really want to clear all preferred directions?", mtWarning, Buttons, 0) == mrNo)
2080  {
2081  Utilities->CallLogPop(24);
2082  return;
2083  }
2084  // leave all as was before pressed DeleteAllPrefDirButton
2085  else
2086  {
2091  SetLevel1Mode(5);
2092  }
2093  Utilities->CallLogPop(25);
2094  }
2095  catch(const Exception &e)
2096  {
2097  ErrorLog(11, e.Message);
2098  }
2099 }
2100 // ---------------------------------------------------------------------------
2101 
2102 void __fastcall TInterface::DeleteOnePrefDirButtonClick(TObject *Sender)
2103 {
2104  try
2105  {
2106  TrainController->LogEvent("DeleteOnePrefDirButtonClick");
2107  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteOnePrefDirButtonClick");
2108  ResetChangedFileDataAndCaption(18, false);
2109 // RlyFile = false; - don't alter this just for PrefDir changes
2110  Screen->Cursor = TCursor(-11); // Hourglass;
2111  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
2112  {
2115  }
2118  SetLevel1Mode(81); // all PrefDir truncated
2119  Screen->Cursor = TCursor(-2); // Arrow
2120  Utilities->CallLogPop(1591);
2121  }
2122  catch(const Exception &e)
2123  {
2124  ErrorLog(46, e.Message);
2125  }
2126 }
2127 
2128 // ---------------------------------------------------------------------------
2129 
2130 void __fastcall TInterface::ExitPrefDirButtonClick(TObject *Sender)
2131 {
2132  try
2133  {
2134  TrainController->LogEvent("ExitPrefDirButtonClick");
2135  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitPrefDirButtonClick");
2136  Level1Mode = BaseMode;
2137  SetLevel1Mode(6);
2138  Utilities->CallLogPop(1554);
2139  }
2140  catch(const Exception &e)
2141  {
2142  ErrorLog(133, e.Message);
2143  }
2144 }
2145 
2146 // ---------------------------------------------------------------------------
2147 // Operate Railway Interface
2148 // ---------------------------------------------------------------------------
2149 void __fastcall TInterface::OperateRailwayMenuItemClick(TObject *Sender) // Mode Menu Item
2150 {
2151  try
2152  {
2153  TrainController->LogEvent("OperateRailwayMenuItemClick");
2154  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperateRailwayMenuItemClick");
2155  TTrain::NextTrainID = 0; // reset to 0 whenever enter operating mode
2156  AllRoutes->NextRouteID = 0; // reset to 0 whenever enter operating mode
2157  Level1Mode = OperMode;
2158  SetLevel1Mode(7);
2159  Utilities->CallLogPop(26);
2160  }
2161  catch(const Exception &e)
2162  {
2163  ErrorLog(12, e.Message);
2164  }
2165 }
2166 
2167 // ---------------------------------------------------------------------------
2168 void __fastcall TInterface::OperateButtonClick(TObject *Sender)
2169 {
2170  try
2171  {
2172  TrainController->LogEvent("StartOperationButtonClick");
2173  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperateButtonClick");
2175  {
2177  SetLevel2OperMode(0);
2178  }
2179  else
2180  {
2182  SetLevel2OperMode(1);
2183  }
2184  Utilities->CallLogPop(1175);
2185  }
2186  catch(const Exception &e)
2187  {
2188  ErrorLog(37, e.Message);
2189  }
2190 }
2191 
2192 // ---------------------------------------------------------------------------
2193 void __fastcall TInterface::AutoSigsButtonClick(TObject *Sender)
2194 // must have PrefDirs to be available
2195 {
2196  try
2197  {
2198  TrainController->LogEvent("AutoSigsButtonClick");
2199  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AutoSigsButtonClick");
2200  AutoSigsFlag = true;
2201  PreferredRoute = true;
2202  ConsecSignalsRoute = true;
2203 
2204  AutoSigsButton->Enabled = false;
2205  SigPrefConsecButton->Enabled = true;
2206  SigPrefNonConsecButton->Enabled = true;
2207  UnrestrictedButton->Enabled = true;
2208 
2209  InfoPanel->Visible = true;
2210  if(Level2OperMode == PreStart)
2211  {
2212  InfoPanel->Caption = "PRE-START: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
2213  }
2214  else
2215  {
2216  InfoPanel->Caption = "OPERATING: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
2217  }
2218  InfoCaptionStore = InfoPanel->Caption;
2219  AutoRouteStartMarker->PlotOriginal(1, Display); // if overlay not plotted will ignore
2220  SigRouteStartMarker->PlotOriginal(2, Display); // if overlay not plotted will ignore
2221  NonSigRouteStartMarker->PlotOriginal(3, Display); // if overlay not plotted will ignore
2223  Utilities->CallLogPop(28);
2224  }
2225  catch(const Exception &e)
2226  {
2227  ErrorLog(14, e.Message);
2228  }
2229 }
2230 
2231 // ---------------------------------------------------------------------------
2232 
2233 void __fastcall TInterface::SigPrefConsecButtonClick(TObject *Sender)
2234 // must have PrefDirs to be available
2235 {
2236  try
2237  {
2238  TrainController->LogEvent("SigPrefButtonClick");
2239  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigPrefButtonClick");
2240  AutoSigsFlag = false;
2241  PreferredRoute = true;
2242  ConsecSignalsRoute = true;
2243 
2244  AutoSigsButton->Enabled = true;
2245  SigPrefConsecButton->Enabled = false;
2246  SigPrefNonConsecButton->Enabled = true;
2247  UnrestrictedButton->Enabled = true;
2248 
2249  InfoPanel->Visible = true;
2250  if(Level2OperMode == PreStart)
2251  {
2252  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
2253  }
2254  else
2255  {
2256  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
2257  }
2258  InfoCaptionStore = InfoPanel->Caption;
2259  AutoRouteStartMarker->PlotOriginal(43, Display); // if overlay not plotted will ignore
2260  SigRouteStartMarker->PlotOriginal(44, Display); // if overlay not plotted will ignore
2261  NonSigRouteStartMarker->PlotOriginal(45, Display); // if overlay not plotted will ignore
2263  Utilities->CallLogPop(2265);
2264  }
2265  catch(const Exception &e)
2266  {
2267  ErrorLog(221, e.Message);
2268  }
2269 }
2270 
2271 // ---------------------------------------------------------------------------
2272 
2273 void __fastcall TInterface::SigPrefNonConsecButtonClick(TObject *Sender)
2274 // must have PrefDirs to be available
2275 {
2276  try
2277  {
2278  TrainController->LogEvent("SigPrefButtonClick");
2279  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigPrefButtonClick");
2280  AutoSigsFlag = false;
2281  PreferredRoute = true;
2282  ConsecSignalsRoute = false;
2283 
2284  AutoSigsButton->Enabled = true;
2285  SigPrefConsecButton->Enabled = true;
2286  SigPrefNonConsecButton->Enabled = false;
2287  UnrestrictedButton->Enabled = true;
2288 
2289  InfoPanel->Visible = true;
2290  if(Level2OperMode == PreStart)
2291  {
2292  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
2293  }
2294  else
2295  {
2296  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
2297  }
2298  InfoCaptionStore = InfoPanel->Caption;
2299  AutoRouteStartMarker->PlotOriginal(4, Display); // if overlay not plotted will ignore
2300  SigRouteStartMarker->PlotOriginal(5, Display); // if overlay not plotted will ignore
2301  NonSigRouteStartMarker->PlotOriginal(6, Display); // if overlay not plotted will ignore
2303  Utilities->CallLogPop(29);
2304  }
2305  catch(const Exception &e)
2306  {
2307  ErrorLog(15, e.Message);
2308  }
2309 }
2310 
2311 // ---------------------------------------------------------------------------
2312 void __fastcall TInterface::UnrestrictedButtonClick(TObject *Sender)
2313 {
2314  try
2315  {
2316  TrainController->LogEvent("NoSigNonPrefButtonClick");
2317  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NoSigNonPrefButtonClick");
2318  AutoSigsFlag = false;
2319  PreferredRoute = false;
2320  ConsecSignalsRoute = false;
2321  if(EveryPrefDir->PrefDirSize() > 0)
2322  {
2323  AutoSigsButton->Enabled = true;
2324  SigPrefConsecButton->Enabled = true;
2325  SigPrefNonConsecButton->Enabled = true;
2326  UnrestrictedButton->Enabled = false;
2327  }
2328  else
2329  {
2330  AutoSigsButton->Enabled = false;
2331  SigPrefConsecButton->Enabled = false;
2332  SigPrefNonConsecButton->Enabled = false;
2333  UnrestrictedButton->Enabled = false;
2334  }
2335  InfoPanel->Visible = true;
2336  if(Level2OperMode == PreStart)
2337  {
2338  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
2339  }
2340  else
2341  {
2342  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
2343  }
2344  InfoCaptionStore = InfoPanel->Caption;
2345  AutoRouteStartMarker->PlotOriginal(7, Display); // if overlay not plotted will ignore
2346  SigRouteStartMarker->PlotOriginal(8, Display); // if overlay not plotted will ignore
2347  NonSigRouteStartMarker->PlotOriginal(9, Display); // if overlay not plotted will ignore
2349  Utilities->CallLogPop(30);
2350  }
2351  catch(const Exception &e)
2352  {
2353  ErrorLog(16, e.Message);
2354  }
2355 }
2356 
2357 // ---------------------------------------------------------------------------
2358 void __fastcall TInterface::RouteCancelButtonClick(TObject *Sender)
2359 {
2360  try
2361  {
2362  TrainController->LogEvent("RouteCancelButtonClick");
2363  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RouteCancelButtonClick");
2364  RouteCancelFlag = true;
2365  InfoPanel->Visible = true;
2366  InfoPanel->Caption = "ROUTE CANCELLING: Right click on truncate element, first element to cancel (anywhere else to skip)";
2367  RouteCancelButton->Enabled = false;
2368  AutoRouteStartMarker->PlotOriginal(32, Display); // if overlay not plotted will ignore
2369  SigRouteStartMarker->PlotOriginal(33, Display); // if overlay not plotted will ignore
2370  NonSigRouteStartMarker->PlotOriginal(34, Display); // if overlay not plotted will ignore
2371  Utilities->CallLogPop(1176);
2372  }
2373  catch(const Exception &e)
2374  {
2375  ErrorLog(35, e.Message);
2376  }
2377 }
2378 
2379 // ---------------------------------------------------------------------------
2380 void __fastcall TInterface::PerformanceLogButtonClick(TObject *Sender)
2381 {
2382  try
2383  {
2384  TrainController->LogEvent("PerformanceLogButtonClick");
2385  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformanceLogButtonClick");
2387  {
2388  ShowPerformancePanel = true;
2389  PerformancePanel->Visible = true;
2390  PerformanceLogButton->Glyph->LoadFromResourceName(0, "HideLog");
2391  }
2392  else
2393  {
2394  ShowPerformancePanel = false;
2395  PerformancePanel->Visible = false;
2396  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
2397  }
2398  Utilities->CallLogPop(1177);
2399  }
2400  catch(const Exception &e)
2401  {
2402  ErrorLog(36, e.Message);
2403  }
2404 }
2405 // ---------------------------------------------------------------------------
2406 
2407 void __fastcall TInterface::ExitOperationButtonClick(TObject *Sender)
2408 {
2409  try
2410  {
2411  TrainController->LogEvent("ExitOperationButtonClick");
2412  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitOperationButtonClick");
2414  {
2415  UnicodeString MessageStr = "Please note that the session will be lost if it hasn't been saved. Do you still wish to exit?";
2416  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2418  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
2419  TrainController->BaseTime = TDateTime::CurrentDateTime();
2421  if(button == IDNO)
2422  {
2423  Utilities->CallLogPop(751);
2424  return;
2425  }
2426  }
2427  Track->ResetSignals(1);
2428  Track->ResetPoints(1);
2429  TrainController->SendPerformanceSummary(0, Utilities->PerformanceFile); // must come before trains finished becuase examines the train vectors
2430  Utilities->PerformanceFile.close();
2433  RouteMode = None;
2434  PreferredRoute = true; // default starting conditions
2435  ConsecSignalsRoute = true; // default starting conditions
2437  ShowPerformancePanel = false;
2438  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
2439  ShowOperatorActionPanel = false; // new at v2.2.0
2440  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel"); // new v2.2.0
2441  PerformanceLogBox->Lines->Clear();
2442  PerformancePanel->Visible = false;
2443  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
2444  PerformancePanel->Left = MainScreen->Left;
2445 // TipButton->Glyph->LoadFromResourceName(0, "ShowLog"); //'Trains in play' new at v2.2.0
2446  OAListBox->Clear();
2447  OperatorActionPanel->Visible = false;
2448  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height;
2449  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width;
2450  ;
2452  AllRoutes->LockedRouteVector.clear();
2453  Level1Mode = BaseMode;
2454  SetLevel1Mode(8); // calls Clearand...
2455  Utilities->CallLogPop(1555);
2456  }
2457  catch(const Exception &e)
2458  {
2459  ErrorLog(13, e.Message);
2460  }
2461 }
2462 
2463 // ---------------------------------------------------------------------------
2464 // Menu Interface (for items not already covered above)
2465 // ---------------------------------------------------------------------------
2466 void __fastcall TInterface::LoadRailwayMenuItemClick(TObject *Sender)
2467 {
2468  try
2469  {
2470  TrainController->LogEvent("LoadRailwayMenuItemClick");
2471  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LoadRailwayMenuItemClick");
2472  if(!ClearEverything(1))
2473  {
2474  Utilities->CallLogPop(1139);
2475  return;
2476  }
2477  // LoadRailwayDialog->Filter = "Development file (*.dev)|*.dev|Railway file (*.rly)|*.rly"; //as was
2478  // changed at v2.0.0 (Embarcadero change) to show all files together
2479  LoadRailwayDialog->Filter = "Railway files (*.rly or *.dev)|*.rly; *.dev";
2480  if(LoadRailwayDialog->Execute())
2481  {
2482  if(LoadRailwayDialog->InitialDir != TPath::GetDirectoryName(LoadRailwayDialog->FileName)) // new at v2.6.0 to retain a new directory
2483  {
2484  LoadRailwayDialog->InitialDir = TPath::GetDirectoryName(LoadRailwayDialog->FileName);
2485  SaveRailwayDialog->InitialDir = TPath::GetDirectoryName(LoadRailwayDialog->FileName);
2486  }
2487  TrainController->LogEvent("LoadRailway " + AnsiString(LoadRailwayDialog->FileName));
2488  LoadRailway(0, AnsiString(LoadRailwayDialog->FileName));
2489  }
2490  // else ShowMessage("Load Aborted"); drop this
2491  // Display->Update(); //display updated in ClearandRebuildRailway
2492  Track->CalcHLocMinEtc(9);
2493  Level1Mode = BaseMode;
2496  SetLevel1Mode(11); // calls Clearand... to plot the new railway
2497  Utilities->CallLogPop(31);
2498  }
2499  catch(const Exception &e)
2500  {
2501  ErrorLog(17, e.Message);
2502  }
2503 }
2504 // ---------------------------------------------------------------------------
2505 
2506 void TInterface::LoadRailway(int Caller, AnsiString LoadFileName)
2507 {
2508  // display of the loaded railway covered in the calling routine
2509  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRailway," + LoadFileName);
2510  if(FileIntegrityCheck(0, LoadFileName.c_str()))
2511  {
2512  Screen->Cursor = TCursor(-11); // Hourglass;
2513  std::ifstream VecFile(LoadFileName.c_str());
2514  if(!(VecFile.fail()))
2515  {
2516  AnsiString TempString = Utilities->LoadFileString(VecFile); // version number
2517  int TempOffsetHHome = Utilities->LoadFileInt(VecFile);
2518  int TempOffsetVHome = Utilities->LoadFileInt(VecFile);
2519  bool GraphicsFollow = false;
2520  // can't load DisplayOffsetH & VHome until after LoadTrack as that calls TrackClear & zeroes them
2521 // load track elements
2522  Track->LoadTrack(1, VecFile, GraphicsFollow);
2523 // load text elements
2524  TextHandler->LoadText(0, VecFile);
2525 // load PrefDir elements
2526  EveryPrefDir->LoadPrefDir(0, VecFile);
2527  if(GraphicsFollow)
2528  {
2529 // load user graphics
2530  Track->LoadGraphics(0, VecFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME); // include path to Graphics folder
2531  }
2532  EveryPrefDir->CheckPrefDirAgainstTrackVector(0); // clears PrefDir if any discrepancies found
2533  VecFile.close();
2534  Display->DisplayOffsetHHome = TempOffsetHHome;
2535  Display->DisplayOffsetVHome = TempOffsetVHome;
2537 
2538  TFont *TempFont = new TFont; // if try to alter MainScreen->Canvas->Font directly it won't change the style for some reason
2539  TempFont->Style.Clear();
2540  TempFont->Name = "MS Sans Serif"; // reset font, else stays set to last displayed text font
2541  TempFont->Size = 10;
2542  TempFont->Color = clB0G0R0;
2543  TempFont->Charset = (TFontCharset)(0);
2544  MainScreen->Canvas->Font->Assign(TempFont);
2545  delete TempFont;
2546 
2547 // calculate starting zoomed out offset values - same as when zoom out button clicked
2548  int OVOffH_NVCentre = Display->DisplayOffsetH - (1.5 * Utilities->ScreenElementWidth);
2549 // start zoomout centre at DisplayOffsetH + 30 - zoomout width/2 = -(1.5 * 60)
2550  int LeftExcess = OVOffH_NVCentre - Track->GetHLocMin();
2551  int RightExcess = Track->GetHLocMax() - OVOffH_NVCentre - ((4 * Utilities->ScreenElementWidth) - 1);
2552  if((LeftExcess > 0) && (RightExcess > 0))
2553  {
2554  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre;
2555  }
2556  else if((LeftExcess > 0) && (RightExcess <= 0))
2557  {
2558  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre + ((RightExcess) / (Utilities->ScreenElementWidth / 2)) *
2559  (Utilities->ScreenElementWidth / 2); // normalise to nearest half screen
2560  }
2561  else if((LeftExcess <= 0) && (RightExcess > 0))
2562  {
2563  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre - ((LeftExcess) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2);
2564  }
2565  else
2566  {
2567  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre; // no excess at either side, so display in centre
2568 
2569  }
2570  int OVOffV_NVCentre = Display->DisplayOffsetV - (1.5 * Utilities->ScreenElementHeight);
2571  int TopExcess = OVOffV_NVCentre - Track->GetVLocMin();
2572  int BotExcess = Track->GetVLocMax() - OVOffV_NVCentre - ((4 * Utilities->ScreenElementHeight) - 1);
2573  if((TopExcess > 0) && (BotExcess > 0))
2574  {
2575  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre;
2576  }
2577  else if((TopExcess > 0) && (BotExcess <= 0))
2578  {
2579  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre + ((BotExcess) / (Utilities->ScreenElementHeight / 2)) *
2580  (Utilities->ScreenElementHeight / 2); // normalise to nearest half screen
2581  }
2582  else if((TopExcess <= 0) && (BotExcess > 0))
2583  {
2584  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre - ((TopExcess) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2);
2585  }
2586  else
2587  {
2588  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre; // no excess at either side, so display in centre
2589  }
2590 // all above same as when zoom out button clicked
2591  Display->DisplayZoomOutOffsetVHome = Display->DisplayZoomOutOffsetV; // now set zoomed out 'home' values
2593 
2594  SavedFileName = AnsiString(LoadRailwayDialog->FileName); // includes the full PrefDir
2595  if(SavedFileName != "") // shouldn't be "" at this stage but leave in as a safeguard
2596  {
2597  Track->DuplicatedLocationName(1, true);
2598  char LastChar = SavedFileName[SavedFileName.Length()];
2599  if((LastChar == 'y') || (LastChar == 'Y'))
2600  {
2601  if(!(Track->IsReadyForOperation(false)))
2602  {
2603  ShowMessage("Railway not ready for operation so unable to load as a .rly file. Loading as a new railway under development");
2604  SavedFileName = "";
2605  RlyFile = false;
2606  RailwayTitle = "";
2607  TimetableTitle = "";
2608  SetCaption(5);
2609  Track->CalcHLocMinEtc(1);
2610  Screen->Cursor = TCursor(-2); // Arrow
2611  Level1Mode = BaseMode;
2612  SetLevel1Mode(9);
2613  session_api_->dump(); // update session INI file //added at v2.10.0
2614  Utilities->CallLogPop(1136);
2615  return;
2616  }
2617  else
2618  {
2619  RlyFile = true;
2620  }
2621  }
2622  else
2623  {
2624  RlyFile = false;
2625  }
2626  }
2627  else
2628  {
2629  RlyFile = false;
2630  }
2631  FileChangedFlag = false;
2632  for(int x = AnsiString(LoadRailwayDialog->FileName).Length(); x > 0; x--)
2633  {
2634  if(AnsiString(LoadRailwayDialog->FileName)[x] == '\\')
2635  {
2636  RailwayTitle = AnsiString(LoadRailwayDialog->FileName).SubString(x + 1, AnsiString(LoadRailwayDialog->FileName).Length() - x - 4);
2637  TimetableTitle = "";
2638  SetCaption(6);
2639  break;
2640  }
2641  }
2642  } // if(VecFile)
2643  else
2644  {
2645  ShowMessage("File open failed prior to load");
2646  }
2647  Screen->Cursor = TCursor(-2); // Arrow
2648  } // if(FileIntegrityCheck(LoadRailwayDialog->FileName.c_str()))
2649  else
2650  {
2651  ShowMessage("File integrity check failed - unable to load " + LoadFileName + ". Please check that the file exists and is spelled correctly.");
2652  }
2653  session_api_->dump(); // update session INI file //added at v2.10.0
2654  Utilities->CallLogPop(1774);
2655 }
2656 
2657 // ---------------------------------------------------------------------------
2658 
2659 void __fastcall TInterface::SaveMenuItemClick(TObject *Sender)
2660 {
2661 // save under existing name
2662 // no need to alter RlyFile for saving under existing name
2663 
2664  try
2665  {
2666  TrainController->LogEvent("SaveMenuItemClick, " + SavedFileName);
2667  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveMenuItemClick");
2668  Screen->Cursor = TCursor(-11); // Hourglass;
2669  std::ofstream VecFile(SavedFileName.c_str());
2670  if(!(VecFile.fail()))
2671  {
2675  // save track elements
2676  if(Track->UserGraphicVector.empty())
2677  {
2678  Track->SaveTrack(3, VecFile, false); // false for no graphics (**Active elements** saved as marker)
2679  }
2680  else
2681  {
2682  Track->SaveTrack(8, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
2683  }
2684  // save text elements
2685  TextHandler->SaveText(0, VecFile);
2686  // save PrefDir elements
2687  EveryPrefDir->SavePrefDirVector(0, VecFile);
2688  if(!Track->UserGraphicVector.empty())
2689  {
2690  // save user graphics
2691  Track->SaveUserGraphics(0, VecFile);
2692  }
2693  FileChangedFlag = false;
2694  VecFile.close();
2695  }
2696  else
2697  {
2698  ShowMessage("File open failed prior to save");
2699  }
2700  Screen->Cursor = TCursor(-2); // Arrow
2701  Level1Mode = BaseMode;
2702  SetLevel1Mode(12); // to disable the save option
2703  Utilities->CallLogPop(1178);
2704  }
2705  catch(const Exception &e)
2706  {
2707  ErrorLog(135, e.Message);
2708  }
2709 }
2710 
2711 // ---------------------------------------------------------------------------
2712 void __fastcall TInterface::SaveAsMenuItemClick(TObject *Sender)
2713 {
2714  try
2715  {
2716  TrainController->LogEvent("SaveAsMenuItemClick");
2717  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveAsMenuItemClick");
2718  SaveAsSubroutine(0);
2719  Utilities->CallLogPop(32);
2720  }
2721  catch(const Exception &e)
2722  {
2723  ErrorLog(18, e.Message);
2724  }
2725 }
2726 
2727 // ---------------------------------------------------------------------------
2728 
2729 void __fastcall TInterface::SaveImageNoGridMenuItemClick(TObject *Sender)
2730 {
2731  // need to stop clock in case invoke during operation
2732  try
2733  {
2734  TrainController->LogEvent("SaveImageNoGridMenuItemClick");
2735  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageNoGridMenuItemClick");
2736  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2737  {
2738  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2739  Utilities->CallLogPop(1695);
2740  return;
2741  }
2742  Screen->Cursor = TCursor(-11); // Hourglass;
2743  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2745  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2746  // format "16/06/2009 20:55:17"
2747  // avoid characters in filename:= / \ : * ? " < > |
2748  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2749  AnsiString ShortName = "";
2750  for(int x = ImageFileName.Length(); x > 0; x--)
2751  {
2752  if(ImageFileName[x] == '\\')
2753  {
2754  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2755  break;
2756  }
2757  }
2758  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2759  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2760  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2761 
2762  int HPosMin = Track->GetHLocMin() * 16;
2763  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2764  int VPosMin = Track->GetVLocMin() * 16;
2765  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2766  RailwayImage->Width = HPosMax - HPosMin;
2767  RailwayImage->Height = VPosMax - VPosMin;
2768 
2769  // need to check if there is any text that extends past HPosMax or below VPosMax
2770  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2771  if(!TextHandler->TextVector.empty())
2772  {
2773  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2774  {
2775  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2776  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2777  if(NewWidth > RailwayImage->Width)
2778  {
2779  RailwayImage->Width = NewWidth;
2780  }
2781  if(NewHeight > RailwayImage->Height)
2782  {
2783  RailwayImage->Height = NewHeight;
2784  }
2785  }
2786  }
2787  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2788  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2789  RailwayImage->Canvas->FillRect(Rect);
2790 
2791  // write graphics first so text & track overwrite
2792  Track->WriteGraphicsToImage(0, RailwayImage);
2793  // then write track & text so text overwrites graphics & inactive elements //changed name & added text after inactives at v2.10.0
2794  Track->WriteTrackAndTextToImage(0, RailwayImage);
2795 
2796  RailwayImage->SaveToFile(ImageFileName);
2797  delete RailwayImage;
2798  TrainController->BaseTime = TDateTime::CurrentDateTime();
2800  Screen->Cursor = TCursor(-2); // Arrow
2801  Utilities->CallLogPop(1535);
2802  }
2803  catch(const Exception &e) //non-error catch
2804  {
2805  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2806  {
2807  Screen->Cursor = TCursor(-2); // Arrow;
2808  UnicodeString MessageStr = "Insufficient memory available to store this image";
2809  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2810  Utilities->CallLogPop(2297);
2811  }
2812  else
2813  {
2814  ErrorLog(42, e.Message);
2815  }
2816  }
2817 }
2818 
2819 // ---------------------------------------------------------------------------
2820 
2821 void __fastcall TInterface::SaveImageAndGridMenuItemClick(TObject *Sender)
2822 {
2823  // need to stop clock in case invoke during operation
2824  try
2825  {
2826  TrainController->LogEvent("SaveImageAndGridMenuItemClick");
2827  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageAndGridMenuItemClick");
2828  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2829  {
2830  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2831  Utilities->CallLogPop(1696);
2832  return;
2833  }
2834  Screen->Cursor = TCursor(-11); // Hourglass;
2835  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2837  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2838  // format "16/06/2009 20:55:17"
2839  // avoid characters in filename:= / \ : * ? " < > |
2840  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2841  AnsiString ShortName = "";
2842  for(int x = ImageFileName.Length(); x > 0; x--)
2843  {
2844  if(ImageFileName[x] == '\\')
2845  {
2846  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2847  break;
2848  }
2849  }
2850  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2851  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2852  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2853  int HPosMin = Track->GetHLocMin() * 16;
2854  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2855  int VPosMin = Track->GetVLocMin() * 16;
2856  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2857  RailwayImage->Width = HPosMax - HPosMin;
2858  RailwayImage->Height = VPosMax - VPosMin;
2859 
2860  // need to check if there is any text that extends past HPosMax or below VPosMax
2861  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2862  if(!TextHandler->TextVector.empty())
2863  {
2864  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2865  {
2866  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2867  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2868  if(NewWidth > RailwayImage->Width)
2869  {
2870  RailwayImage->Width = NewWidth;
2871  }
2872  if(NewHeight > RailwayImage->Height)
2873  {
2874  RailwayImage->Height = NewHeight;
2875  }
2876  }
2877  }
2878  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2879  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2880  RailwayImage->Canvas->FillRect(Rect);
2881 
2882  // write the grid first so all else on top
2883  for(int x = 0; x < ((RailwayImage->Width) / 16); x++)
2884  {
2885  for(int y = 0; y < ((RailwayImage->Height) / 16); y++)
2886  {
2887  RailwayImage->Canvas->Draw((x * 16), (y * 16), RailGraphics->bmGrid); // graphic is black on white so no need to change
2888  }
2889  }
2890  // write graphics next so text & track overwrite
2891  Track->WriteGraphicsToImage(1, RailwayImage);
2892  // then write track & text so text overwrites graphics & inactive elements
2893  Track->WriteTrackAndTextToImage(1, RailwayImage); //changed name & added text after inactives at v2.10.0
2894  RailwayImage->SaveToFile(ImageFileName);
2895  delete RailwayImage;
2896  TrainController->BaseTime = TDateTime::CurrentDateTime();
2898  Screen->Cursor = TCursor(-2); // Arrow
2899  Utilities->CallLogPop(1536);
2900  }
2901  catch(const Exception &e) //non-error catch
2902  {
2903  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2904  {
2905  Screen->Cursor = TCursor(-2); // Arrow;
2906  UnicodeString MessageStr = "Insufficient memory available to store this image";
2907  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2908  Utilities->CallLogPop(2298);
2909  }
2910  else
2911  {
2912  ErrorLog(43, e.Message);
2913  }
2914  }
2915 }
2916 // ---------------------------------------------------------------------------
2917 
2918 void __fastcall TInterface::SaveImageAndPrefDirsMenuItemClick(TObject *Sender)
2919 {
2920  // need to stop clock in case invoke during operation
2921  try
2922  {
2923  TrainController->LogEvent("SaveImageAndPrefDirsMenuItemClick");
2924  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageAndPrefDirsMenuItemClick");
2925  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2926  {
2927  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2928  Utilities->CallLogPop(1697);
2929  return;
2930  }
2931  Screen->Cursor = TCursor(-11); // Hourglass;
2932  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2934  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2935  // format "16/06/2009 20:55:17"
2936  // avoid characters in filename:= / \ : * ? " < > |
2937  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2938  AnsiString ShortName = "";
2939  for(int x = ImageFileName.Length(); x > 0; x--)
2940  {
2941  if(ImageFileName[x] == '\\')
2942  {
2943  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2944  break;
2945  }
2946  }
2947  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2948  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2949  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2950  int HPosMin = Track->GetHLocMin() * 16;
2951  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2952  int VPosMin = Track->GetVLocMin() * 16;
2953  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2954  RailwayImage->Width = HPosMax - HPosMin;
2955  RailwayImage->Height = VPosMax - VPosMin;
2956 
2957  // need to check if there is any text that extends past HPosMax or below VPosMax
2958  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2959  if(!TextHandler->TextVector.empty())
2960  {
2961  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2962  {
2963  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2964  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2965  if(NewWidth > RailwayImage->Width)
2966  {
2967  RailwayImage->Width = NewWidth;
2968  }
2969  if(NewHeight > RailwayImage->Height)
2970  {
2971  RailwayImage->Height = NewHeight;
2972  }
2973  }
2974  }
2975  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2976  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2977  RailwayImage->Canvas->FillRect(Rect);
2978 
2979  // write graphics first so text & track overwrite
2980  Track->WriteGraphicsToImage(2, RailwayImage);
2981  // then write track & text so text overwrites graphics & inactive elements
2982  Track->WriteTrackAndTextToImage(2, RailwayImage); //changed name & added text after inactives at v2.10.0
2983  EveryPrefDir->WritePrefDirToImage(0, RailwayImage);
2984  RailwayImage->SaveToFile(ImageFileName);
2985  delete RailwayImage;
2986  TrainController->BaseTime = TDateTime::CurrentDateTime();
2988  Screen->Cursor = TCursor(-2); // Arrow
2989  Utilities->CallLogPop(1566);
2990  }
2991  catch(const Exception &e) //non-error catch
2992  {
2993  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2994  {
2995  Screen->Cursor = TCursor(-2); // Arrow;
2996  UnicodeString MessageStr = "Insufficient memory available to store this image";
2997  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2998  Utilities->CallLogPop(2299);
2999  }
3000  else
3001  {
3002  ErrorLog(45, e.Message);
3003  }
3004  }
3005 }
3006 // ---------------------------------------------------------------------------
3007 
3008 void __fastcall TInterface::SaveOperatingImageMenuItemClick(TObject *Sender)
3009 {
3010  // need to stop clock
3011  try
3012  {
3013  TrainController->LogEvent("SaveOperatingImageMenuItemClick");
3014  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveOperatingImageMenuItemClick");
3015  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
3016  {
3017  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
3018  Utilities->CallLogPop(1702);
3019  return;
3020  }
3021  Screen->Cursor = TCursor(-11); // Hourglass;
3022  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
3024 
3025  AnsiString TimetableTimeStr = Utilities->Format96HHMMSS(TrainController->TTClockTime);
3026  TimetableTimeStr = TimetableTimeStr.SubString(1, 2) + '.' + TimetableTimeStr.SubString(4, 2) + '.' + TimetableTimeStr.SubString(7, 2);
3027  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
3028  // format "16/06/2009 20:55:17"
3029  // avoid characters in filename:= / \ : * ? " < > |
3030  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
3031  "; " + TimetableTitle + ".bmp";
3032  AnsiString ShortName = "";
3033  for(int x = ImageFileName.Length(); x > 0; x--)
3034  {
3035  if(ImageFileName[x] == '\\')
3036  {
3037  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
3038  break;
3039  }
3040  }
3041  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
3042  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
3043  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
3044  int HPosMin = Track->GetHLocMin() * 16;
3045  int HPosMax = (Track->GetHLocMax() + 1) * 16;
3046  int VPosMin = Track->GetVLocMin() * 16;
3047  int VPosMax = (Track->GetVLocMax() + 1) * 16;
3048  RailwayImage->Width = HPosMax - HPosMin;
3049  RailwayImage->Height = VPosMax - VPosMin;
3050 
3051  // need to check if there is any text that extends past HPosMax or below VPosMax
3052  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
3053  if(!TextHandler->TextVector.empty())
3054  {
3055  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
3056  {
3057  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
3058  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
3059  if(NewWidth > RailwayImage->Width)
3060  {
3061  RailwayImage->Width = NewWidth;
3062  }
3063  if(NewHeight > RailwayImage->Height)
3064  {
3065  RailwayImage->Height = NewHeight;
3066  }
3067  }
3068  }
3069  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
3070  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
3071  RailwayImage->Canvas->FillRect(Rect);
3072 
3073  // write graphics first so text & track overwrite
3074  Track->WriteGraphicsToImage(3, RailwayImage);
3075  // then write track and text so both overwrite graphics & text overwrites inactive elements
3076  Track->WriteOperatingTrackAndTextToImage(0, RailwayImage); // need points with single fillets, signals with colours, gaps all connected
3077  AllRoutes->WriteAllRoutesToImage(0, RailwayImage);
3078 // add any locked route markers
3079  if(!AllRoutes->LockedRouteVector.empty())
3080  {
3081  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
3082  {
3083  TOneRoute Route = AllRoutes->GetFixedRouteAt(167, LRVIT->RouteNumber);
3084  int x = Route.PrefDirSize() - 1;
3085  bool BreakFlag = false;
3086  TPrefDirElement PrefDirElement = Route.GetFixedPrefDirElementAt(188, x);
3087  while(PrefDirElement.GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
3088  {
3089  RailwayImage->Canvas->Draw((PrefDirElement.HLoc - Track->GetHLocMin()) * 16, (PrefDirElement.VLoc - Track->GetVLocMin()) * 16,
3090  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
3091  if(!(AllRoutes->TrackIsInARoute(13, PrefDirElement.Conn[PrefDirElement.GetELinkPos()],
3092  PrefDirElement.ConnLinkPos[PrefDirElement.GetELinkPos()])))
3093  {
3094  BreakFlag = true;
3095  break; // train removed earlier element from route so stop here
3096  }
3097  x--;
3098  PrefDirElement = Route.GetFixedPrefDirElementAt(180, x);
3099  }
3100  if(!BreakFlag)
3101  {
3102  if(PrefDirElement.GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
3103  {
3104  RailwayImage->Canvas->Draw((PrefDirElement.HLoc - Track->GetHLocMin()) * 16, (PrefDirElement.VLoc - Track->GetVLocMin()) * 16,
3105  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
3106  }
3107  }
3108  }
3109  }
3110  TrainController->WriteTrainsToImage(0, RailwayImage);
3111  RailwayImage->SaveToFile(ImageFileName);
3112  delete RailwayImage;
3113  TrainController->BaseTime = TDateTime::CurrentDateTime();
3115  Screen->Cursor = TCursor(-2); // Arrow
3116  Utilities->CallLogPop(1703);
3117  }
3118  catch(const Exception &e) //non-error catch
3119  {
3120  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
3121  {
3122  Screen->Cursor = TCursor(-2); // Arrow;
3123  UnicodeString MessageStr = "Insufficient memory available to store this image";
3124  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
3125  Utilities->CallLogPop(2300);
3126  }
3127  else
3128  {
3129  ErrorLog(113, e.Message); // NB: DO NOT CHANGE THIS ERROR NUMBER - THE DISPLAYED MESSAGE DEPENDS ON IT
3130  }
3131  }
3132 }
3133 
3134 // ---------------------------------------------------------------------------
3135 
3136 void __fastcall TInterface::SaveHeaderMenu1Click(TObject *Sender)
3137 {
3138 //
3139  try
3140  {
3141  TrainController->LogEvent("SaveHeaderMenu1Click");
3142  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveHeaderMenu1Click");
3143  if(Sender == SaveSessionButton)
3144  {
3145  SaveSessionFlag = true;
3146  }
3147  else if(SavedFileName == "") // use 'Save As' function
3148  {
3149  SaveAsSubroutine(1);
3150  }
3151  else // ordinary save
3152  {
3153  Screen->Cursor = TCursor(-11); // Hourglass;
3154  std::ofstream VecFile(SavedFileName.c_str());
3155  if(!(VecFile.fail()))
3156  {
3160  // save track elements
3161  if(Track->UserGraphicVector.empty())
3162  {
3163  Track->SaveTrack(9, VecFile, false); // false for no graphics (**Active elements** saved as marker)
3164  }
3165  else
3166  {
3167  Track->SaveTrack(10, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
3168  }
3169  // save text elements
3170  TextHandler->SaveText(5, VecFile);
3171  // save PrefDir elements
3172  EveryPrefDir->SavePrefDirVector(8, VecFile);
3173  if(!Track->UserGraphicVector.empty())
3174  {
3175  // save user graphics
3176  Track->SaveUserGraphics(1, VecFile);
3177  }
3178  FileChangedFlag = false;
3179  VecFile.close();
3180  }
3181  else
3182  {
3183  ShowMessage("Railway failed to save - can't open file");
3184  }
3185  Screen->Cursor = TCursor(-2); // Arrow
3186  }
3187  Utilities->CallLogPop(1552);
3188  }
3189  catch(const Exception &e)
3190  {
3191  ErrorLog(44, e.Message);
3192  }
3193 }
3194 
3195 // ---------------------------------------------------------------------------
3196 void __fastcall TInterface::LoadSessionMenuItemClick(TObject *Sender)
3197 {
3198  try
3199  {
3200  TrainController->LogEvent("LoadSessionMenuItemClick");
3201  LoadSessionFlag = true; // load session within ClockTimer2
3202  }
3203  catch(const Exception &e)
3204  {
3205  ErrorLog(136, e.Message);
3206  }
3207 }
3208 
3209 // ---------------------------------------------------------------------------
3210 void __fastcall TInterface::ClearAllMenuItemClick(TObject *Sender)
3211 {
3212  try
3213  {
3214  TrainController->LogEvent("ClearAllMenuItemClick");
3215  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ClearAllMenuItemClick");
3216  if(ClearEverything(2))
3217  {
3218  ;
3219  } // no change in action on result
3220 
3221  Level1Mode = BaseMode;
3222  SetLevel1Mode(126);
3223  Utilities->CallLogPop(1179);
3224  }
3225  catch(const Exception &e)
3226  {
3227  ErrorLog(137, e.Message);
3228  }
3229 }
3230 
3231 // ---------------------------------------------------------------------------
3232 void __fastcall TInterface::ExportTTMenuItemClick(TObject *Sender)
3233 {
3234  // no need to stop clock as can't be called when railway operating
3235  try
3236  {
3237  TrainController->LogEvent("ExportTTMenuItemClick");
3238  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExportTTMenuItemClick");
3239  if(!DirectoryExists(CurDir + "\\" + FORMATTEDTT_DIR_NAME))
3240  {
3241  ShowMessage("Failed to find folder " + FORMATTEDTT_DIR_NAME + " in the folder where 'railway.exe' resides. Timetable can't be exported");
3242  Utilities->CallLogPop(1699);
3243  return;
3244  }
3245 // Screen->Cursor = TCursor(-11); // Hourglass; - no good setting here as it's reset by ShowMessage in CreateFormattedTimetable. It's set there after
3246 // the message instead, but reset here afterwards
3247  // no need to stop clock as can't select this if operating
3249  Screen->Cursor = TCursor(-2); // Arrow - reset after above function returns
3250  Utilities->CallLogPop(1573);
3251  }
3252  catch(const Exception &e)
3253  {
3254  ErrorLog(138, e.Message);
3255  }
3256 }
3257 // ---------------------------------------------------------------------------
3258 // Timetable editing functions
3259 
3260 /* Note that during early development the timetable was created outside the program as a .csv file using Excel, it was only later that
3261  the editing functions within the program were developed. Much of the original structure was preserved though to avoid rewriting the
3262  code interpretation functions in TrainUnit.cpp. This is why commas are used as service event separators, and why it is necessary to
3263  convert them to CRLFs for display and back again for internal storage. It is acknowledged that all this makes the editing functions
3264  somewhat cumbersome, and, as ever, if I was starting again I wouldn't do it like that!
3265 
3266  CR & LF review:
3267  These cause problems by the way that different subroutines handle them.
3268 
3269  AnsiStrings can incorporate CRLFs, but the end of an AnsiString is marked by a '\0' character as in 'C' strings.
3270 
3271  In the fstream functions 'getline(char_type* s, streamsize n)' extracts characters from the stream and puts them in buffer 's' until
3272  (a) n-1 characters are stored + '\0' after the n-1 characters;
3273  (b) a '\n' (CRLF) character is found in the stream, in which case a '\0' is added to the buffer after the text that immediately
3274  precedes the CRLF in the stream; and
3275  (c) an eof() is found in the stream, in which case a '\0' is added to the buffer at the end of the text.
3276  Note that if no characters are stored a '\0' is still stored in position [0] of the buffer.
3277 
3278  The << operator in ofstreams, when used with a null terminated string, doesn't store the null. If it is required it has to be
3279  sent explicitly, e.g. file << '\0'. Presumably the same applies for CRLF terminated strings.
3280 
3281 */
3282 // ---------------------------------------------------------------------------
3283 
3284 void __fastcall TInterface::CreateTimetableMenuItemClick(TObject *Sender)
3285 {
3286  try
3287  {
3288  TrainController->LogEvent("CreateTimetableMenuItemClick");
3289  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CreateTimetableMenuItemClick");
3290  CreateEditTTFileName = "";
3291  TimetableEditVector.clear();
3292  TimetableEditPanel->Visible = true;
3293  TrainController->TTEditPanelVisible = true; // added at v2.6.0 for two location message
3294  HighlightPanel->Visible = false;
3295  TimetablePanel->Visible = true;
3296  TimetablePanel->BringToFront(); // in case SaveRailway button visible, want it hidden else obscures the panel text
3297  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3298  OneEntryTimetableMemo->Clear();
3299  AllEntriesTTListBox->Clear();
3300  TTStartTimeBox->Text = "";
3301  AddSubMinsBox->Text = "";
3303  LocationNameComboBox->Clear();
3304  TimetableTitle = ""; // unload any loaded timetable. Added here at v2.1.0
3305  TrainController->TrainDataVector.clear(); // unload any loaded timetable. Added here at v2.1.0
3306  SetCaption(9); // added at v2.1.0 as formerly retained earlier loaded tt name in error
3307  TimetableChangedFlag = false;
3308  TimetableValidFlag = false;
3309  TTEntryChangedFlag = false;
3311  AZOrderButton->Caption = AnsiString("A-Z Order");
3312  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
3313  CopiedEntryFlag = false;
3314  NewEntryInPreparationFlag = false;
3315  CopiedEntryStr = "";
3316  TEVPtr = 0;
3317  TTCurrentEntryPtr = 0;
3318  TTStartTimePtr = 0;
3319  TTFirstServicePtr = 0;
3320  TTLastServicePtr = 0; // all set to null to begin with
3321 
3322 // populate LocationNameComboBox if a railway is loaded, but first compile the ActiveTrackElementNameMap
3323  TTrack::TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
3325  for(unsigned int x = 0; x < Track->TrackVector.size(); x++)
3326  {
3328  == Track->ContinuationNameMap.end())
3329  {
3330  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
3331  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1038, x).ActiveTrackElementName;
3332  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
3333  Track->ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
3334  }
3335  }
3337  if(!(Track->ActiveTrackElementNameMap.empty()))
3338  {
3339  LocationNameComboBox->Text = "Location names";
3340 // new version at beta v0.2b
3342  ATENIT++)
3343  {
3344  LocationNameComboBox->Items->Add(ATENIT->first); // continuations excluded during compilation, but a location that includes
3345  // continuations as well as other track will be included - earlier version
3346  // would have excluded them
3347  }
3348 
3349 /* old version using LocationNameMultiMap, changed to use ActiveTrackElementNames to avoid including lone concourses and named non-station
3350  locations
3351  TStringList *StringList = new TStringList;
3352  StringList->Clear();//probably already empty but help file doesn't say so
3353  StringList->Sorted = false;//for now
3354  for(TTrack::TLocationNameMultiMapIterator LNMIT = Track->LocationNameMultiMap.begin(); LNMIT != Track->LocationNameMultiMap.end(); LNMIT++)
3355  {
3356  NewKey = LNMIT->first;
3357  if(OldKey != NewKey)//only add new values
3358  {
3359  if(Track->ContinuationNameMap.find(NewKey) == Track->ContinuationNameMap.end())//not a continuation
3360  {
3361  StringList->Add(NewKey);
3362  OldKey = NewKey;
3363  }
3364  }
3365  }
3366  StringList->Sort();
3367  for(int x=0;x<StringList->Count;x++)
3368  {
3369  LocationNameComboBox->Items->Add(StringList->Strings[x]);
3370  }
3371  delete StringList;
3372 */
3373  }
3374  else
3375  {
3376  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
3377  }
3379  SetLevel1Mode(82);
3380  session_api_->dump(); // update session INI file //added at v2.10.0
3381  Utilities->CallLogPop(1595);
3382  }
3383  catch(const Exception &e)
3384  {
3385  ErrorLog(47, e.Message);
3386  }
3387 }
3388 
3389 // ---------------------------------------------------------------------------
3390 void __fastcall TInterface::EditTimetableMenuItemClick(TObject *Sender)
3391 /* The .ttb file contains a sequence of AnsiStrings separated by null characters. CRLFs may be embedded within the AnsiStrings,
3392  * to cause newlines when displayed. Each AnsiString corresponds to a timetable 'entry'
3393 */
3394 {
3395  try
3396  {
3397  TrainController->LogEvent("EditTimetableMenuItemClick");
3398  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EditTimetableMenuItemClick");
3399  SigImagePanel->Visible = false; // stop panel showing while waiting for name entry
3400  TimetableDialog->Filter = "Timetable file (*.ttb)|*ttb";
3401  CreateEditTTFileName = "";
3402  TimetableEditVector.clear();
3403  TimetableEditPanel->Visible = true;
3404  TrainController->TTEditPanelVisible = true; // added at v2.6.0 for two location message
3405  HighlightPanel->Visible = false;
3406  TimetablePanel->Visible = true;
3407  TimetablePanel->BringToFront(); // in case SaveRailway button visible, want it hidden else obscures the panel text
3408  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3409  OneEntryTimetableMemo->Clear();
3410  AllEntriesTTListBox->Clear();
3411  TTStartTimeBox->Text = "";
3412  AddSubMinsBox->Text = "";
3414  LocationNameComboBox->Clear();
3415  TimetableTitle = ""; // unload any loaded timetable. Moved here from below at v2.1.0 for consistency with CreateTimetable
3416  TrainController->TrainDataVector.clear(); // unload any loaded timetable. Moved here from below at v2.1.0 for consistency with CreateTimetable
3417  SetCaption(8); // added at v2.1.0 as formerly retained earlier loaded tt name in error
3418  TEVPtr = 0;
3420  TTFirstServicePtr = 0;
3421  TTLastServicePtr = 0; // all set to null to begin with
3422  if(TimetableDialog->Execute())
3423  {
3424  if(TimetableDialog->InitialDir != TPath::GetDirectoryName(TimetableDialog->FileName)) // new at v2.6.0 to retain a new directory
3425  {
3426  TimetableDialog->InitialDir = TPath::GetDirectoryName(TimetableDialog->FileName);
3427  SaveTTDialog->InitialDir = TPath::GetDirectoryName(TimetableDialog->FileName);
3428  }
3429  CreateEditTTFileName = AnsiString(TimetableDialog->FileName);
3430  TrainController->LogEvent("EditTimetable " + CreateEditTTFileName);
3431  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary); // open in binary to examine each character
3432  if(TTBLFile.is_open())
3433  {
3434  // check doesn't contain any non-ascii characters except CR, LF & '\0', and isn't empty
3435  char c;
3436  while(!TTBLFile.eof())
3437  {
3438  TTBLFile.get(c);
3439  if((c < 32) && (c != 13) && (c != 10) && (c != '\0')) // char is signed by default so values > 127 will be caught as treated as -ve
3440  {
3441  ShowMessage("Timetable file is empty or contains non-ascii characters, codes must be between 20 and 127, or CR or LF");
3442  TTBLFile.close();
3443  Utilities->CallLogPop(1612);
3444  return;
3445  }
3446  }
3447  TTBLFile.close();
3448  }
3449  else
3450  {
3451  ShowMessage("Failed to open timetable file " + CreateEditTTFileName + ", make sure it's spelled correctly, it exists and isn't open in another application");
3452  Utilities->CallLogPop(1597);
3453  return;
3454  }
3455  // reopen again in binary mode so the "\r\n" pairs stay as they are rather than being entered as '\n'
3456  Delay(4, 100); // 100mSec delay between closing & re-opening file
3457  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary);
3458  if(TTBLFile.is_open())
3459  {
3460  TTBLFile.clear(); // to clear eofbit from last read
3461  TTBLFile.seekg(0); // shouldn't be needed but include for safety
3462  TimetableChangedFlag = false;
3463  TimetableValidFlag = false;
3464  TTEntryChangedFlag = false;
3466  AZOrderButton->Caption = AnsiString("A-Z Order");
3467  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
3468  NewEntryInPreparationFlag = false;
3469  CopiedEntryStr = "";
3470  CopiedEntryFlag = false;
3471 // CreateEditTTFileName = TimetableDialog->FileName;
3472  for(int x = CreateEditTTFileName.Length(); x > 0; x--)
3473  {
3474  if(CreateEditTTFileName[x] == '\\')
3475  {
3476  CreateEditTTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
3477  break;
3478  }
3479  }
3480  char *TimetableEntryString = new char[10000];
3481  while(true)
3482  {
3483  TTBLFile.getline(TimetableEntryString, 10000, '\0'); // pick up the entire AnsiString, including any embedded newlines
3484  if(TTBLFile.eof() && (TimetableEntryString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
3485  {
3486  // may still have eof even if read a line, and
3487  // if so need to process it
3488  break;
3489  }
3490  AnsiString OneLine(TimetableEntryString);
3491  TimetableEditVector.push_back(OneLine);
3492  }
3493  TTBLFile.close();
3494  delete[] TimetableEntryString;
3495  // here with TimetableEditVector compiled
3496  }
3497  else
3498  {
3499  ShowMessage("Failed to open timetable file " + CreateEditTTFileName + ", make sure it's spelled correctly, it exists and isn't open in another application");
3500  Utilities->CallLogPop(1654);
3501  return;
3502  }
3503  }
3504  else // cancelled dialog [section prior to CallLogPop added for v1.3.2 to clear timetable screen if cancel button pressed]
3505  {
3506  CreateEditTTFileName = "";
3507 // set to null to allow a check during error file saving, if not null save the tt being edited to the file (see entry in ExitTTModeButtonClick)
3508  CreateEditTTTitle = ""; // as above
3509  Level1Mode = BaseMode;
3510  SetLevel1Mode(132);
3511  Utilities->CallLogPop(1633);
3512  return;
3513  }
3515  if(TimetableEditVector.empty())
3516  {
3518  SetLevel1Mode(89);
3519  Utilities->CallLogPop(1614);
3520  return;
3521  }
3522 // all now set where can be
3524 
3525 // populate LocationNameComboBox if a railway is loaded, but first compile the ActiveTrackElementNameMap
3526  TTrack::TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
3528  for(unsigned int x = 0; x < Track->TrackVector.size(); x++)
3529  {
3531  == Track->ContinuationNameMap.end())
3532  {
3533  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
3534  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1041, x).ActiveTrackElementName;
3535  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
3536  Track->ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
3537  }
3538  }
3540  if(!(Track->ActiveTrackElementNameMap.empty()))
3541  {
3542  LocationNameComboBox->Text = "Location names";
3543 // new version for beta v0.2b
3545  ATENIT++)
3546  {
3547  LocationNameComboBox->Items->Add(ATENIT->first); // continuations excluded during compilation, but a location that includes
3548  // continuations as well as other track will be included - earlier version
3549  // would have excluded them
3550  }
3551  }
3552  else
3553  {
3554  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
3555  }
3557  SetLevel1Mode(83);
3558  session_api_->dump(); // update session INI file //added at v2.10.0
3559  Utilities->CallLogPop(1596);
3560  }
3561  catch(const Exception &e)
3562  {
3563  ErrorLog(48, e.Message);
3564  }
3565 }
3566 // ---------------------------------------------------------------------------
3567 
3568 void __fastcall TInterface::ShowHideTTButtonClick(TObject *Sender)
3569 {
3570  try
3571  {
3572  TrainController->LogEvent("ShowHideTTButtonClick");
3573  if(TimetableEditPanel->Visible)
3574  {
3575  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Show");
3576  TimetableEditPanel->Visible = false;
3577  TrainController->TTEditPanelVisible = false; // added at v2.6.0 for two location message
3578  ShowHideTTButton->Hint = "Show the timetable editor Shift S";
3579 // InfoPanel->Visible = false; //changed at v1.3.0 to make it clearer that still in TT mode
3580  InfoPanel->Caption = "Timetable mode: editor hidden"; // as above
3581  }
3582  else
3583  {
3584  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3585  TimetableEditPanel->Visible = true;
3586  TrainController->TTEditPanelVisible = true; // added at v2.6.0 for two location message
3587  ShowHideTTButton->Hint = "Hide the timetable editor to see the railway Shift H";
3589  SetLevel1Mode(124);
3590  }
3591  }
3592  catch(const Exception &e)
3593  {
3594  ErrorLog(139, e.Message);
3595  }
3596 }
3597 // ---------------------------------------------------------------------------
3598 
3599 void __fastcall TInterface::NextTTEntryButtonClick(TObject *Sender)
3600 {
3601  try
3602  {
3603  TrainController->LogEvent("NextTTEntryButtonClick");
3604  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NextTTEntryButtonClick");
3605  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
3606  {
3607  Utilities->CallLogPop(1683);
3608  return;
3609  }
3610  if(TTCurrentEntryPtr < (TimetableEditVector.end() - 1))
3611  {
3613  }
3614  TTEntryChangedFlag = false;
3615  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3616  // position changing in AllEntriesTTListBox
3618  SetLevel1Mode(85);
3619  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3620  {
3622  }
3623  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3624  {
3625  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3626  }
3627  else
3628  {
3629  AllEntriesTTListBox->TopIndex = TopPos;
3630  }
3631  Utilities->CallLogPop(1605);
3632  }
3633  catch(const Exception &e)
3634  {
3635  ErrorLog(50, e.Message);
3636  }
3637 }
3638 
3639 // ---------------------------------------------------------------------------
3640 void __fastcall TInterface::PreviousTTEntryButtonClick(TObject *Sender)
3641 {
3642  try
3643  {
3644  TrainController->LogEvent("PreviousTTEntryButtonClick");
3645  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PreviousTTEntryButtonClick");
3646  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
3647  {
3648  Utilities->CallLogPop(1684);
3649  return;
3650  }
3652  {
3654  }
3655  TTEntryChangedFlag = false;
3656  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3657  // position changing in AllEntriesTTListBox
3659  SetLevel1Mode(86);
3660  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3661  {
3663  }
3664  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3665  {
3666  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3667  }
3668  else
3669  {
3670  AllEntriesTTListBox->TopIndex = TopPos;
3671  }
3672  Utilities->CallLogPop(1607);
3673  }
3674  catch(const Exception &e)
3675  {
3676  ErrorLog(51, e.Message);
3677  }
3678 }
3679 
3680 // ---------------------------------------------------------------------------
3681 void __fastcall TInterface::NewTTEntryButtonClick(TObject *Sender)
3682 {
3683  try
3684  {
3685  TrainController->LogEvent("NewTTEntryButtonClick");
3686  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NewTTEntryButtonClick");
3687  OneEntryTimetableMemo->Clear();
3688  OneEntryTimetableMemo->SetFocus();
3691  SetLevel1Mode(103);
3692  Utilities->CallLogPop(1615);
3693  }
3694  catch(const Exception &e)
3695  {
3696  ErrorLog(52, e.Message);
3697  }
3698 }
3699 // ---------------------------------------------------------------------------
3700 
3701 void __fastcall TInterface::AddMinsButtonClick(TObject *Sender)
3702 {
3703  try
3704  {
3705  TrainController->LogEvent("AddMinsButtonClick");
3706  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddMinsButtonClick");
3707  bool ValidFlag = true;
3708  for(int x = 1; x <= AddSubMinsBox->Text.Length(); x++)
3709  {
3710  if((AddSubMinsBox->Text[x] > '9') || (AddSubMinsBox->Text[x] < '0')) // tested in TTHandler but check here as a safeguard
3711  {
3712  ValidFlag = false;
3713  break;
3714  }
3715  }
3716  if(ValidFlag)
3717  {
3718  if(AddSubMinsBox->Text.ToInt() == 0)
3719  {
3720  ValidFlag = false;
3721  }
3722  }
3723  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == "") || (AddSubMinsBox->Text == "") || !ValidFlag)
3724  {
3725  Utilities->CallLogPop(1649);
3726  return;
3727  }
3728  TDateTime DummyTime;
3729  int AddMins = AddSubMinsBox->Text.ToInt();
3730  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
3731  {
3732  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
3733  {
3734  if(TrainController->CheckTimeValidity(25, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
3735  {
3736  int Mins = OneEntryTimetableMemo->Lines->Strings[x].SubString(y + 3, 2).ToInt();
3737  int Hrs = OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 2).ToInt();
3738  Mins += AddMins;
3739  while(Mins >= 60)
3740  {
3741  Mins -= 60;
3742  Hrs++;
3743  }
3744  if(Hrs > 95)
3745  {
3746  ShowMessage("One or more times excessive, not permitted to exceed 95 hours");
3747  Utilities->CallLogPop(1650);
3748  return;
3749  }
3750  AnsiString MinsStr = AnsiString(Mins), HrsStr = AnsiString(Hrs);
3751  if(Mins < 10)
3752  {
3753  MinsStr = "0" + MinsStr;
3754  }
3755  if(Hrs < 10)
3756  {
3757  HrsStr = "0" + HrsStr;
3758  }
3759  int StrLength = OneEntryTimetableMemo->Lines->Strings[x].Length();
3760  AnsiString NewString = OneEntryTimetableMemo->Lines->Strings[x].SubString(1, (y - 1)); // up to but not including the time
3761  NewString += HrsStr + ':' + MinsStr;
3762  NewString += OneEntryTimetableMemo->Lines->Strings[x].SubString((y + 5), (StrLength - y - 4));
3763  OneEntryTimetableMemo->Lines->Strings[x] = NewString;
3764  }
3765  }
3766  }
3767 
3768  OneEntryTimetableMemo->HideSelection = true;
3769  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
3770  OneEntryTimetableMemo->SelLength = 0;
3771  TimetableValidFlag = false;
3772  TimetableChangedFlag = true;
3773  TTEntryChangedFlag = true;
3775  SetLevel1Mode(91);
3776  Utilities->CallLogPop(1617);
3777  }
3778  catch(const Exception &e)
3779  {
3780  ErrorLog(54, e.Message);
3781  }
3782 }
3783 // ---------------------------------------------------------------------------
3784 
3785 void __fastcall TInterface::SubMinsButtonClick(TObject *Sender)
3786 {
3787  try
3788  {
3789  TrainController->LogEvent("SubMinsButtonClick");
3790  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SubMinsButtonClick");
3791  bool ValidFlag = true;
3792  for(int x = 1; x <= AddSubMinsBox->Text.Length(); x++)
3793  {
3794  if((AddSubMinsBox->Text[x] > '9') || (AddSubMinsBox->Text[x] < '0')) // tested in TTHandler but check here as a safeguard
3795  {
3796  ValidFlag = false;
3797  break;
3798  }
3799  }
3800  if(ValidFlag)
3801  {
3802  if(AddSubMinsBox->Text.ToInt() == 0)
3803  {
3804  ValidFlag = false;
3805  }
3806  }
3807  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == "") || (AddSubMinsBox->Text == "") || !ValidFlag)
3808  {
3809  Utilities->CallLogPop(1659);
3810  return;
3811  }
3812  TDateTime DummyTime;
3813  int SubMins = AddSubMinsBox->Text.ToInt();
3814  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
3815  {
3816  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
3817  {
3818  if(TrainController->CheckTimeValidity(28, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
3819  {
3820  int Mins = OneEntryTimetableMemo->Lines->Strings[x].SubString(y + 3, 2).ToInt();
3821  int Hrs = OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 2).ToInt();
3822  Mins -= SubMins;
3823  while(Mins < 0)
3824  {
3825  Mins += 60;
3826  Hrs--;
3827  }
3828  if(Hrs < 0)
3829  {
3830  ShowMessage("One or more times are now before 00:00, this is not permitted");
3831  Utilities->CallLogPop(1660);
3832  return;
3833  }
3834  AnsiString MinsStr = AnsiString(Mins), HrsStr = AnsiString(Hrs);
3835  if(Mins < 10)
3836  {
3837  MinsStr = "0" + MinsStr;
3838  }
3839  if(Hrs < 10)
3840  {
3841  HrsStr = "0" + HrsStr;
3842  }
3843  int StrLength = OneEntryTimetableMemo->Lines->Strings[x].Length();
3844  AnsiString NewString = OneEntryTimetableMemo->Lines->Strings[x].SubString(1, (y - 1)); // up to but not including the time
3845  NewString += HrsStr + ':' + MinsStr;
3846  NewString += OneEntryTimetableMemo->Lines->Strings[x].SubString((y + 5), (StrLength - y - 4));
3847  OneEntryTimetableMemo->Lines->Strings[x] = NewString;
3848  }
3849  }
3850  }
3851  OneEntryTimetableMemo->HideSelection = true;
3852  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
3853  OneEntryTimetableMemo->SelLength = 0;
3854  TimetableValidFlag = false;
3855  TimetableChangedFlag = true;
3856  TTEntryChangedFlag = true;
3858  SetLevel1Mode(92);
3859  Utilities->CallLogPop(1618);
3860  }
3861  catch(const Exception &e)
3862  {
3863  ErrorLog(55, e.Message);
3864  }
3865 }
3866 // ---------------------------------------------------------------------------
3867 
3868 void __fastcall TInterface::CopyTTEntryButtonClick(TObject *Sender)
3869 {
3870  try
3871  {
3872  TrainController->LogEvent("CopyTTEntryButtonClick");
3873  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CopyTTEntryButtonClick");
3874  if(TTCurrentEntryPtr == 0)
3875  {
3876  Utilities->CallLogPop(1636);
3877  return;
3878  }
3880  CopiedEntryFlag = true;
3881  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3882  // position changing in AllEntriesTTListBox
3884  SetLevel1Mode(93);
3885  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3886  {
3888  }
3889  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3890  {
3891  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3892  }
3893  else
3894  {
3895  AllEntriesTTListBox->TopIndex = TopPos;
3896  }
3897  Utilities->CallLogPop(1619);
3898  }
3899  catch(const Exception &e)
3900  {
3901  ErrorLog(56, e.Message);
3902  }
3903 }
3904 // ---------------------------------------------------------------------------
3905 
3906 void __fastcall TInterface::CutTTEntryButtonClick(TObject *Sender)
3907 {
3908  try
3909  {
3910  TrainController->LogEvent("CutTTEntryButtonClick");
3911  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CutTTEntryButtonClick");
3912  if(TTCurrentEntryPtr == 0) // || (*TTCurrentEntryPtr == ""))//safeguard
3913  {
3914  Utilities->CallLogPop(1674);
3915  return;
3916  }
3918  CopiedEntryFlag = true;
3919  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an erase,
3920  // so use the position in the vector
3922 // now need to rebuild all the pointers & the AllEntriesTTListBox so repeat the process from EditTimetableMenuItemClick
3923 // pick up the start time if there is one
3924  TimetableChangedFlag = true;
3925  TimetableValidFlag = false;
3926  TTEntryChangedFlag = false;
3927  TEVPtr = 0;
3929  TTFirstServicePtr = 0;
3930  TTLastServicePtr = 0; // all set to null to begin with
3931  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3932  // position changing in AllEntriesTTListBox
3933  AllEntriesTTListBox->Clear();
3935  if(TimetableEditVector.empty())
3936  {
3938  SetLevel1Mode(109);
3939  Utilities->CallLogPop(1777);
3940  return;
3941  }
3942 // reset the TTCurrentEntryPtr to the Entry before the erased one if there is one //was 'after', changed at v2.5.0
3943 // but vector pointers unreliable after an erase, so use the position in the vector
3944  if(OldVectorPos == 0)
3945  {
3947  }
3948  else
3949  {
3950  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos - 1;
3951  }
3952  if(TTCurrentEntryPtr == 0)
3953  {
3954  OneEntryTimetableMemo->Clear();
3955  }
3957  SetLevel1Mode(115);
3958  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3959  {
3961  }
3962  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3963  {
3964  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3965  }
3966  else
3967  {
3968  AllEntriesTTListBox->TopIndex = TopPos;
3969  }
3970  Utilities->CallLogPop(1676);
3971  }
3972  catch(const Exception &e)
3973  {
3974  ErrorLog(111, e.Message);
3975  }
3976 }
3977 
3978 // ---------------------------------------------------------------------------
3979 void __fastcall TInterface::PasteTTEntryButtonClick(TObject *Sender)
3980 {
3981  try
3982  {
3983  TrainController->LogEvent("PasteTTEntryButtonClick");
3984  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PasteTTEntryButtonClick");
3985  if(TTCurrentEntryPtr == 0) // || (CopiedEntryStr == "")) allow blank copies
3986  {
3987  Utilities->CallLogPop(1637);
3988  return;
3989  }
3990  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
3991  TimetableEditVector.insert(TTCurrentEntryPtr + 1, CopiedEntryStr); // inserts before the indicated pointer position, i.e. immediately
3992  // after the current Entry - may be at the end
3993  TimetableChangedFlag = true;
3994  TimetableValidFlag = false;
3995  TTEntryChangedFlag = false;
3996  TEVPtr = 0;
3998  TTFirstServicePtr = 0;
3999  TTLastServicePtr = 0; // all set to null to begin with
4000  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4001  // position changing in AllEntriesTTListBox
4002  AllEntriesTTListBox->Clear();
4004  if(TimetableEditVector.empty())
4005  {
4007  SetLevel1Mode(110);
4008  Utilities->CallLogPop(1778);
4009  return;
4010  }
4011 // restore TTCurrentEntryPtr
4012  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4013  TTCurrentEntryPtr++; // advance the pointer to the pasted entry
4014 // CopiedEntryStr = "";//revert to null - no, allow multiple copies
4016  SetLevel1Mode(94);
4017  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4018  {
4020  }
4021  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4022  {
4023  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4024  }
4025  else
4026  {
4027  AllEntriesTTListBox->TopIndex = TopPos;
4028  }
4029  Utilities->CallLogPop(1620);
4030  }
4031  catch(const Exception &e)
4032  {
4033  ErrorLog(57, e.Message);
4034  }
4035 }
4036 // ---------------------------------------------------------------------------
4037 
4038 void __fastcall TInterface::DeleteTTEntryButtonClick(TObject *Sender)
4039 {
4040  try
4041  {
4042  TrainController->LogEvent("DeleteTTEntryButtonClick");
4043  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteTTEntryButtonClick");
4044  if(TTCurrentEntryPtr == 0)
4045  {
4046  Utilities->CallLogPop(1645);
4047  return;
4048  }
4049  UnicodeString MessageStr = "Are you sure this entry should be deleted?";
4050  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
4051  if(button == IDNO)
4052  {
4053  Utilities->CallLogPop(1663);
4054  return;
4055  }
4056  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an erase,
4057  // so use the position in the vector
4059 
4060 // now need to rebuild all the pointers & the AllEntriesTTListBox so repeat the process from EditTimetableMenuItemClick
4061 // pick up the start time if there is one
4062  TimetableChangedFlag = true;
4063  TimetableValidFlag = false;
4064  TTEntryChangedFlag = false;
4065  TEVPtr = 0;
4067  TTFirstServicePtr = 0;
4068  TTLastServicePtr = 0; // all set to null to begin with
4069  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4070  // position changing in AllEntriesTTListBox
4071  AllEntriesTTListBox->Clear();
4073  if(TimetableEditVector.empty())
4074  {
4076  SetLevel1Mode(111);
4077  Utilities->CallLogPop(1779);
4078  return;
4079  }
4080 // reset the TTCurrentEntryPtr to the Entry before the erased one if there is one
4081 // but vector pointers unreliable after an erase, so use the position in the vector
4082  if(OldVectorPos == 0)
4083  {
4085  }
4086  else
4087  {
4088  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos - 1;
4089  }
4090  if(TTCurrentEntryPtr == 0)
4091  {
4092  OneEntryTimetableMemo->Clear();
4093  }
4095  SetLevel1Mode(95);
4096  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4097  {
4099  }
4100  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4101  {
4102  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4103  }
4104  else
4105  {
4106  AllEntriesTTListBox->TopIndex = TopPos;
4107  }
4108  Utilities->CallLogPop(1621);
4109  }
4110  catch(const Exception &e)
4111  {
4112  ErrorLog(58, e.Message);
4113  }
4114 }
4115 // ---------------------------------------------------------------------------
4116 
4117 void __fastcall TInterface::SaveTTEntryButtonClick(TObject *Sender)
4118 {
4119  try
4120  {
4121  TrainController->LogEvent("SaveTTEntryButtonClick");
4122  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTEntryButtonClick");
4123 /* allow blank lines to be saved
4124  AnsiString ContentStr = OneEntryTimetableMemo->Text;
4125  if((ContentStr == "\r\n") || (ContentStr == "\n") || (ContentStr == ""))
4126  {
4127  Utilities->CallLogPop(1679);
4128  return;
4129  }
4130 */
4131  AnsiString TempStr = "";
4132  bool ActiveLine = false;
4133  if(TTCurrentEntryPtr > 0)
4134  {
4135  if(*TTCurrentEntryPtr != "")
4136  {
4138  {
4139  ActiveLine = true;
4140  // need to add commas after each line in OneEntryTimetableMemo exept the last, where have '\0'
4141  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
4142  {
4143  for(int y = 1; y <= OneEntryTimetableMemo->Lines->Strings[x].Length(); y++)
4144  {
4145  TempStr += OneEntryTimetableMemo->Lines->Strings[x][y];
4146  }
4147  if(x < (OneEntryTimetableMemo->Lines->Count - 1))
4148  {
4149  TempStr += ',';
4150  }
4151  // No need to add a '\n' as a '\0' is added automatically as a string delimiter. If add '\n' then it is treated as a blank line and
4152  // ends the timetable
4153  }
4154  // strip any excess commas from the end
4155  if(TempStr != "")
4156  {
4157  while(TempStr[TempStr.Length()] == ',')
4158  {
4159  TempStr = TempStr.SubString(1, TempStr.Length() - 1);
4160  if(TempStr == "")
4161  {
4162  break;
4163  }
4164  }
4165  }
4166  }
4167  }
4168  }
4169  if(!ActiveLine)
4170  {
4171  TempStr = OneEntryTimetableMemo->Text; // Note that if the entry was intended as a service but goes in as plain text because
4172  // the service & entry pointers aren't yet set, then CRLFs will be converted to commas in
4173  // CompileAllEntriesMemoAndSetPointers if it appears after the start time
4174  // and before a blank line or end of file, so the syntax check will work OK
4175  }
4176  if(AZOrderButton->Caption == AnsiString("Original Order"))
4177  {
4179  }
4180  TimetableValidFlag = false;
4181  TimetableChangedFlag = true;
4182  TTEntryChangedFlag = false;
4183  int TopPos;
4184  if(TTCurrentEntryPtr == 0)
4185  {
4187  }
4189  {
4190  (*TTCurrentEntryPtr) = TempStr;
4191  // need to reset the AllEntriesTTListBox in case the headcode has changed
4192  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
4193  TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4194  // position changing in AllEntriesTTListBox
4195  AllEntriesTTListBox->Clear();
4197  if(TimetableEditVector.empty())
4198  {
4200  SetLevel1Mode(112);
4201  Utilities->CallLogPop(1780);
4202  return;
4203  }
4204  // restore TTCurrentEntryPtr
4205  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4206  }
4207  else
4208  {
4209  NewEntryInPreparationFlag = false;
4210  if(TTCurrentEntryPtr != 0)
4211  {
4212  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
4213  TimetableEditVector.insert(TTCurrentEntryPtr + 1, TempStr); // inserts before the indicated pointer position, which may be at the end
4214  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4216  }
4217  else
4218  {
4219  TimetableEditVector.insert(TimetableEditVector.end(), TempStr); // inserts before the indicated pointer position
4221  }
4222  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the current position
4223  TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4224  // position changing in AllEntriesTTListBox
4225  AllEntriesTTListBox->Clear();
4227  if(TimetableEditVector.empty())
4228  {
4230  SetLevel1Mode(113);
4231  Utilities->CallLogPop(1781);
4232  return;
4233  }
4234 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4235  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4236  {
4238  }
4239  else
4240  {
4241  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4242  }
4243  }
4245  SetLevel1Mode(96);
4246  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4247  {
4249  }
4250  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4251  {
4252  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4253  }
4254  else
4255  {
4256  AllEntriesTTListBox->TopIndex = TopPos;
4257  }
4258  Utilities->CallLogPop(1622);
4259  }
4260  catch(const Exception &e)
4261  {
4262  ErrorLog(59, e.Message);
4263  }
4264 }
4265 // ---------------------------------------------------------------------------
4266 
4267 void __fastcall TInterface::SaveTTButtonClick(TObject *Sender)
4268 {
4269  try
4270  {
4271  TrainController->LogEvent("SaveTTButtonClick");
4272  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTButtonClick");
4273  if(TimetableEditVector.empty())
4274  {
4275  ShowMessage("Timetable is empty, can't save an empty timetable");
4276  Utilities->CallLogPop(1685);
4277  return;
4278  }
4279  std::ofstream TTBLFile;
4280  if(CreateEditTTFileName != "")
4281  {
4282  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
4283  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
4284  }
4285  else
4286  {
4287  if(SaveTTDialog->Execute())
4288  {
4289  if(SaveTTDialog->InitialDir != TPath::GetDirectoryName(SaveTTDialog->FileName)) // new at v2.6.0 to retain a new directory
4290  {
4291  TimetableDialog->InitialDir = TPath::GetDirectoryName(SaveTTDialog->FileName);
4292  SaveTTDialog->InitialDir = TPath::GetDirectoryName(SaveTTDialog->FileName);
4293  }
4294  CreateEditTTFileName = AnsiString(SaveTTDialog->FileName);
4295  for(int x = CreateEditTTFileName.Length(); x > 0; x--)
4296  {
4297  if(CreateEditTTFileName[x] == '\\')
4298  {
4299  CreateEditTTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
4300  break;
4301  }
4302  }
4303  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
4304  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
4305  }
4306  else // cancelled dialog
4307  {
4309  SetLevel1Mode(137);
4310  Utilities->CallLogPop(2205);
4311  return;
4312  }
4313  }
4314  if(TTBLFile.is_open())
4315  {
4316  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
4317  {
4318  TTBLFile << (*TEVPtr).c_str() << '\0';
4319  }
4320  TimetableChangedFlag = false;
4321  TTBLFile.close();
4322  }
4323  else
4324  {
4325  ShowMessage(CreateEditTTFileName + " failed to open, ensure not already open in another application");
4326  }
4328  SetLevel1Mode(97);
4329  Utilities->CallLogPop(1623);
4330  }
4331  catch(const Exception &e)
4332  {
4333  ErrorLog(60, e.Message);
4334  }
4335 }
4336 // ---------------------------------------------------------------------------
4337 
4338 void __fastcall TInterface::SaveTTAsButtonClick(TObject *Sender)
4339 {
4340  try
4341  {
4342  TrainController->LogEvent("SaveTTAsButtonClick");
4343  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTAsButtonClick");
4344  if(TimetableEditVector.empty())
4345  {
4346  ShowMessage("Timetable is empty, can't save an empty timetable");
4347  Utilities->CallLogPop(1686);
4348  return;
4349  }
4350  std::ofstream TTBLFile;
4351  if(SaveTTDialog->Execute())
4352  {
4353  if(SaveTTDialog->InitialDir != TPath::GetDirectoryName(SaveTTDialog->FileName)) // new at v2.6.0 to retain a new directory
4354  {
4355  TimetableDialog->InitialDir = TPath::GetDirectoryName(SaveTTDialog->FileName);
4356  SaveTTDialog->InitialDir = TPath::GetDirectoryName(SaveTTDialog->FileName);
4357  }
4358  CreateEditTTFileName = SaveTTDialog->FileName;
4359  for(int x = SaveTTDialog->FileName.Length(); x > 0; x--)
4360  {
4361  if(SaveTTDialog->FileName[x] == '\\')
4362  {
4363  CreateEditTTTitle = SaveTTDialog->FileName.SubString(x + 1, SaveTTDialog->FileName.Length() - x - 4);
4364  break;
4365  }
4366  }
4367  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
4368  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
4369  }
4370  else // cancelled dialog
4371  {
4373  SetLevel1Mode(138);
4374  Utilities->CallLogPop(2206);
4375  return;
4376  }
4377  if(TTBLFile.is_open())
4378  {
4379  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
4380  {
4381  TTBLFile << (*TEVPtr).c_str() << '\0';
4382  }
4383  TimetableChangedFlag = false;
4384  TTBLFile.close();
4385  }
4386  else
4387  {
4388  ShowMessage(CreateEditTTFileName + " failed to open, ensure not already open in another application");
4389  }
4391  SetLevel1Mode(117);
4392  Utilities->CallLogPop(1667);
4393  }
4394  catch(const Exception &e)
4395  {
4396  ErrorLog(108, e.Message);
4397  }
4398 }
4399 // ---------------------------------------------------------------------------
4400 
4401 void __fastcall TInterface::TTServiceSyntaxCheckButtonClick(TObject *Sender)
4402 {
4403  try
4404  {
4405  TrainController->LogEvent("TTServiceSyntaxCheckButtonClick");
4406  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTServiceSyntaxCheckButtonClick");
4407  int Count = 1; // anything > 0 OK as if 0 still seeking a start time
4408  bool EndOfFile = false;
4409  bool FinalCallFalse = false;
4410  bool GiveMessagesTrue = true;
4411  bool CheckLocationsExistInRailway = false;
4412  if(RlyFile)
4413  {
4414  CheckLocationsExistInRailway = true;
4415  }
4416 // TrainController->AnyHeadCodeValid = true; //don't fail here because of an unrestricted headcode, if no good will find when validate (dropped at v0.6b)
4417  if(TrainController->ProcessOneTimetableLine(2, Count, *TTCurrentEntryPtr, EndOfFile, FinalCallFalse, GiveMessagesTrue, CheckLocationsExistInRailway))
4418  // return true for success
4419  {
4420  ShowMessage(
4421  "The basic syntax seems OK but this check is very limited. Other aspects can only be checked by validating the whole timetable with the appropriate railway (.rly) loaded");
4422  }
4424  SetLevel1Mode(98);
4425  Utilities->CallLogPop(1624);
4426  }
4427  catch(const Exception &e)
4428  {
4429  ErrorLog(61, e.Message);
4430  }
4431 }
4432 // ---------------------------------------------------------------------------
4433 
4434 void __fastcall TInterface::ValidateTimetableButtonClick(TObject *Sender)
4435 {
4436  try
4437  {
4438  TrainController->LogEvent("ValidateTimetableButtonClick");
4439  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ValidateTimetableButtonClick");
4440  // reset all message flags, stops them being given twice new at v2.4.0
4441  TrainController->SSHigh = false;
4442  TrainController->MRSHigh = false;
4443  TrainController->MRSLow = false;
4444  TrainController->MassHigh = false;
4445  TrainController->BFHigh = false;
4446  TrainController->BFLow = false;
4447  TrainController->PwrHigh = false;
4448  TrainController->SigSHigh = false;
4449  TrainController->SigSLow = false;
4450  if(CreateEditTTFileName == "")
4451  {
4452  Utilities->CallLogPop(1664);
4453  return;
4454  }
4455  bool CheckLocationsExistInRailwayTrue = true;
4456  if(TrainController->TimetableIntegrityCheck(2, CreateEditTTFileName.c_str(), true, CheckLocationsExistInRailwayTrue)) // messages = true
4457  {
4458  Screen->Cursor = TCursor(-11); // Hourglass;
4459  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary);
4460  if(TTBLFile.is_open())
4461  {
4462  if(BuildTrainDataVectorForValidateFile(0, TTBLFile, true, CheckLocationsExistInRailwayTrue)) // messages = true
4463  {
4464  if(!TwoLocationNamePanel->Visible) //added at v2.9.1. If this visible don't override it with another message.
4465  {
4466  ShowMessage("Timetable integrity OK");
4467  TimetableValidFlag = true;
4468  }
4469 // TrainController->TrainDataVector.clear(); keep this so can export a formatted tt
4470  }
4471  }
4472  else
4473  {
4474  ShowMessage("Failed to open timetable file, make sure it's spelled correctly, it exists and isn't open in another application");
4475  }
4476  Screen->Cursor = TCursor(-2); // Arrow
4477  } // if(TimetableIntegrityCheck
4478  else
4479  {
4480 // ShowMessage("Timetable preliminary integrity check failed"); dropped in v2.4.0 as messages given in all called functions
4481  }
4483  SetLevel1Mode(99);
4484  Utilities->CallLogPop(1625);
4485  }
4486  catch(const Exception &e)
4487  {
4488  ErrorLog(62, e.Message);
4489  }
4490 }
4491 
4492 // ---------------------------------------------------------------------------
4493 void __fastcall TInterface::MoveTTEntryUpButtonClick(TObject *Sender)
4494 {
4495  try
4496  {
4497  TrainController->LogEvent("MoveTTEntryUpButtonClick");
4498  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTTEntryUpButtonClick");
4499  if(TTCurrentEntryPtr == 0)
4500  {
4501  Utilities->CallLogPop(1634);
4502  return;
4503  }
4504  if(TTCurrentEntryPtr < (TimetableEditVector.begin() + 1)) // shouldn't reach here but return if do
4505  {
4506  Utilities->CallLogPop(1632);
4507  return;
4508  }
4509  TEVPtr = TTCurrentEntryPtr - 1; // find earlier Entry
4510  AnsiString TempStr = *TEVPtr;
4512  *TTCurrentEntryPtr = TempStr;
4514  TimetableChangedFlag = true;
4515  TimetableValidFlag = false;
4516 
4517 // now rebuild AllEntriesTTListBox, DisplayOneTTLineInPanel will highlight it
4518  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4519  // position changing in AllEntriesTTListBox
4520  AllEntriesTTListBox->Clear();
4521  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4523 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4524  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4525  {
4527  }
4528  else
4529  {
4530  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4531  }
4533  SetLevel1Mode(100);
4534  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4535  {
4537  }
4538  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4539  {
4540  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4541  }
4542  else
4543  {
4544  AllEntriesTTListBox->TopIndex = TopPos;
4545  }
4546  Utilities->CallLogPop(1626);
4547  }
4548  catch(const Exception &e)
4549  {
4550  ErrorLog(63, e.Message);
4551  }
4552 }
4553 // ---------------------------------------------------------------------------
4554 
4555 void __fastcall TInterface::MoveTTEntryDownButtonClick(TObject *Sender)
4556 {
4557  try
4558  {
4559  TrainController->LogEvent("MoveTTEntryDownButtonClick");
4560  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTTEntryDownButtonClick");
4561  if(TTCurrentEntryPtr == 0)
4562  {
4563  Utilities->CallLogPop(1635);
4564  return;
4565  }
4566  if(TTCurrentEntryPtr >= (TimetableEditVector.end() - 1)) // shouldn't reach here but return if do
4567  {
4568  Utilities->CallLogPop(1678);
4569  return;
4570  }
4571  TEVPtr = TTCurrentEntryPtr + 1; // find later Entry
4572  AnsiString TempStr = *TEVPtr;
4574  *TTCurrentEntryPtr = TempStr;
4576  TimetableChangedFlag = true;
4577  TimetableValidFlag = false;
4578 
4579 // now rebuild AllEntriesTTListBox, DisplayOneTTLineInPanel will highlight it
4580  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4581  // position changing in AllEntriesTTListBox
4582  AllEntriesTTListBox->Clear();
4583  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4585 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4586  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4587  {
4589  }
4590  else
4591  {
4592  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4593  }
4595  SetLevel1Mode(101);
4596  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4597  {
4599  }
4600  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4601  {
4602  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4603  }
4604  else
4605  {
4606  AllEntriesTTListBox->TopIndex = TopPos;
4607  }
4608  Utilities->CallLogPop(1627);
4609  }
4610  catch(const Exception &e)
4611  {
4612  ErrorLog(64, e.Message);
4613  }
4614 }
4615 
4616 // ---------------------------------------------------------------------------
4617 void __fastcall TInterface::CancelTTEntryButtonClick(TObject *Sender)
4618 {
4619  try
4620  {
4621  TrainController->LogEvent("CancelTTActionButtonClick");
4622  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CancelTTActionButtonClick");
4623  TTEntryChangedFlag = false;
4625  {
4626  NewEntryInPreparationFlag = false;
4627  OneEntryTimetableMemo->Clear();
4628  }
4629  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4630  // position changing in AllEntriesTTListBox
4632  SetLevel1Mode(102);
4633  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4634  {
4636  }
4637  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4638  {
4639  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4640  }
4641  else
4642  {
4643  AllEntriesTTListBox->TopIndex = TopPos;
4644  }
4645  Utilities->CallLogPop(1630);
4646  }
4647  catch(const Exception &e)
4648  {
4649  ErrorLog(102, e.Message);
4650  }
4651 }
4652 
4653 // ---------------------------------------------------------------------------
4654 void __fastcall TInterface::RestoreTTButtonClick(TObject *Sender)
4655 {
4656  try
4657  {
4658  TrainController->LogEvent("RestoreTTButtonClick");
4659  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RestoreTTButtonClick");
4661  {
4662  UnicodeString MessageStr = "All changes to the timetable will be lost - proceed?";
4663  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
4664  if(button == IDNO)
4665  {
4666  Utilities->CallLogPop(1651);
4667  return;
4668  }
4669  }
4670  // repeat from EditTimetableMenuItemClick, but no need to check for non-ascii characters
4671  // open in binary mode so the "\r\n" pairs stay as they are rather than being entered as '\n'
4672  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary);
4673  if(TTBLFile.is_open())
4674  {
4675  TimetableChangedFlag = false;
4676  TimetableValidFlag = false;
4677  TTEntryChangedFlag = false;
4678  NewEntryInPreparationFlag = false;
4679  CopiedEntryFlag = false;
4680  CopiedEntryStr = "";
4681  TimetableEditVector.clear();
4682  OneEntryTimetableMemo->Clear();
4683  AllEntriesTTListBox->Clear();
4684  TTStartTimeBox->Text = "";
4685  AddSubMinsBox->Text = "";
4686  TEVPtr = 0;
4688  TTFirstServicePtr = 0;
4689  TTLastServicePtr = 0; // all set to null to begin with
4690  char *TimetableEntryString = new char[10000];
4691  while(true)
4692  {
4693  TTBLFile.getline(TimetableEntryString, 10000, '\0'); // pick up the entire AnsiString, including any embedded newlines
4694  if(TTBLFile.eof() && (TimetableEntryString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
4695  {
4696  // may still have eof even if read a line, and
4697  // if so need to process it
4698  break;
4699  }
4700  AnsiString OneLine(TimetableEntryString);
4701  TimetableEditVector.push_back(OneLine);
4702  }
4703  TTBLFile.close();
4704  delete[] TimetableEntryString;
4705  // here with TimetableEditVector compiled
4706  }
4707  else
4708  {
4709  ShowMessage("Failed to open timetable file, make sure it's spelled correctly, it exists and isn't open in another application");
4710  Utilities->CallLogPop(1655);
4711  return;
4712  }
4714  if(TimetableEditVector.empty())
4715  {
4717  SetLevel1Mode(114);
4718  Utilities->CallLogPop(1782);
4719  return;
4720  }
4721 // all now set where can be
4723 // end of repeat from EditTimetableMenuItemClick
4724 
4726  SetLevel1Mode(104);
4727  Utilities->CallLogPop(1652);
4728  }
4729  catch(const Exception &e)
4730  {
4731  ErrorLog(104, e.Message);
4732  }
4733 }
4734 
4735 // ---------------------------------------------------------------------------
4736 void __fastcall TInterface::ExportTTButtonClick(TObject *Sender)
4737 {
4738  try
4739  {
4740  TrainController->LogEvent("ExportTTButtonClick");
4741  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExportTTButtonClick");
4742  if(!DirectoryExists(CurDir + "\\" + FORMATTEDTT_DIR_NAME))
4743  {
4744  ShowMessage("Failed to find folder " + FORMATTEDTT_DIR_NAME + " in the folder where 'railway.exe' resides. Timetable can't be exported");
4745  Utilities->CallLogPop(1698);
4746  return;
4747  }
4748 // Screen->Cursor = TCursor(-11); // Hourglass; - no good setting here as it's reset by ShowMessage in CreateFormattedTimetable. It's set there after
4749 // the message instead, but reset here afterwards
4750  AnsiString TTTitle;
4752  {
4753  for(int x = CreateEditTTFileName.Length(); x > 0; x--) // first need to strip out the timetable title from the full name
4754  {
4755  if(CreateEditTTFileName[x] == '\\')
4756  {
4757  TTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
4758  break;
4759  }
4760  }
4762  }
4763  Screen->Cursor = TCursor(-2); // Arrow - reset after above function returns
4765  SetLevel1Mode(116);
4766  Utilities->CallLogPop(1662);
4767  }
4768  catch(const Exception &e)
4769  {
4770  ErrorLog(107, e.Message);
4771  }
4772 }
4773 
4774 // ---------------------------------------------------------------------------
4775 void __fastcall TInterface::TTTextButtonClick(TObject *Sender)
4776 {
4777  try
4778  {
4779  TrainController->LogEvent("TTTextButtonClick");
4780  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTTextButtonClick");
4781 /*
4782  if(TTStartTimePtr == 0)
4783  {
4784  OneEntryTimetableMemo->Clear();
4785  TTStartTimeBox->SetFocus();
4786  Utilities->CallLogPop(1673);
4787  return;
4788  }
4789 */
4790  int SelPos = OneEntryTimetableMemo->SelStart;
4791  AnsiString FirstPart = OneEntryTimetableMemo->Text.SubString(1, SelPos);
4792  AnsiString LastPart = OneEntryTimetableMemo->Text.SubString(SelPos + 1, OneEntryTimetableMemo->Text.Length() - SelPos);
4793  OneEntryTimetableMemo->Text = FirstPart + ((TButton*)Sender)->Caption + LastPart;
4794  OneEntryTimetableMemo->SelStart = SelPos + ((TButton*)Sender)->Caption.Length();
4795  TTEntryChangedFlag = true;
4796  OneEntryTimetableMemo->SetFocus();
4798  SetLevel1Mode(119);
4799  Utilities->CallLogPop(1672);
4800  }
4801  catch(const Exception &e)
4802  {
4803  ErrorLog(110, e.Message);
4804  }
4805 }
4806 
4807 // ---------------------------------------------------------------------------
4808 void __fastcall TInterface::ExitTTModeButtonClick(TObject *Sender)
4809 {
4810  try
4811  {
4812  TrainController->LogEvent("ExitTTCreateEditButtonClick");
4813  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitTTCreateEditButtonClick");
4815  {
4816  UnicodeString MessageStr = "The timetable has changed.\n\nAre you sure you want to exit without saving it?";
4817  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
4818  if(button == IDNO)
4819  {
4820  Utilities->CallLogPop(1603);
4821  return;
4822  }
4823  }
4824  TimetableChangedFlag = false;
4825  CreateEditTTFileName = ""; // set to null to allow a check during error file saving, if not null save the tt being edited to the file
4826  // added for Beta v0.2b
4827  CreateEditTTTitle = ""; // as above
4828  ConflictPanel->Visible = false;
4829  Level1Mode = BaseMode;
4830  SetLevel1Mode(84);
4831  Utilities->CallLogPop(1606);
4832  }
4833  catch(const Exception &e)
4834  {
4835  ErrorLog(49, e.Message);
4836  }
4837 }
4838 
4839 // ---------------------------------------------------------------------------
4840 void __fastcall TInterface::LocationNameComboBoxClick(TObject *Sender)
4841 {
4842  try
4843  {
4844  TrainController->LogEvent("LocationNameComboBoxClick");
4845  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameComboBoxClick");
4846  if(TTStartTimePtr != 0)
4847  {
4848  LocationNameComboBox->SelectAll();
4849  int SelPos = OneEntryTimetableMemo->SelStart;
4850  AnsiString FirstPart = OneEntryTimetableMemo->Text.SubString(1, SelPos);
4851  AnsiString LastPart = OneEntryTimetableMemo->Text.SubString(SelPos + 1, OneEntryTimetableMemo->Text.Length() - SelPos);
4852  OneEntryTimetableMemo->Text = FirstPart + LocationNameComboBox->SelText + LastPart;
4853  OneEntryTimetableMemo->SelStart = SelPos + LocationNameComboBox->SelText.Length();
4854  TTEntryChangedFlag = true;
4855  OneEntryTimetableMemo->SetFocus();
4857  SetLevel1Mode(118);
4858  }
4859  Utilities->CallLogPop(1669);
4860  }
4861  catch(const Exception &e)
4862  {
4863  ErrorLog(109, e.Message);
4864  }
4865 }
4866 
4867 // ---------------------------------------------------------------------------
4868 void __fastcall TInterface::OneEntryTimetableMemoKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4869 {
4870  try
4871  {
4872 // TrainController->LogEvent("OneEntryTimetableMemoKeyUp"); drop this - too many entries
4873  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OneEntryTimetableMemoKeyUp");
4875  {
4876  Utilities->CallLogPop(1716);
4877  return;
4878  }
4879  TimetableChangedFlag = true;
4880  TTEntryChangedFlag = true;
4881  TimetableValidFlag = false;
4883  SetLevel1Mode(127);
4884  Utilities->CallLogPop(1629);
4885  }
4886  catch(const Exception &e)
4887  {
4888  ErrorLog(66, e.Message);
4889  }
4890 }
4891 
4892 // ---------------------------------------------------------------------------
4893 void __fastcall TInterface::AddSubMinsBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4894 {
4895 // forces a recheck for whether addmins/submins buttons should be enabled
4896  try
4897  {
4898  TrainController->LogEvent("AddSubMinsBoxKeyUp");
4899  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddSubMinsBoxKeyUp");
4901  SetLevel1Mode(108);
4902  Utilities->CallLogPop(1658);
4903  }
4904  catch(const Exception &e)
4905  {
4906  ErrorLog(106, e.Message);
4907  }
4908 }
4909 
4910 // ---------------------------------------------------------------------------
4911 void __fastcall TInterface::LocationNameComboBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4912 {
4913  try
4914  {
4915  TrainController->LogEvent("LocationNameComboBoxKeyUp");
4916  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameComboBoxKeyUp");
4917  if(!Track->LocationNameMultiMap.empty())
4918  {
4919  LocationNameComboBox->Text = "Location names";
4920  }
4921  else
4922  {
4923  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
4924  }
4925  Utilities->CallLogPop(1677);
4926  }
4927  catch(const Exception &e)
4928  {
4929  ErrorLog(112, e.Message);
4930  }
4931 }
4932 
4933 // ---------------------------------------------------------------------------
4934 
4935 void __fastcall TInterface::AllEntriesTTListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
4936 {
4937 // Select the item pointed to unless a 'save entry' is pending in which case ignore
4938  try
4939  {
4940  TrainController->LogEvent("AllEntriesTTListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4941  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AllEntriesTTListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4942  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
4943  {
4944  Utilities->CallLogPop(1687);
4945  return;
4946  }
4947  if(TTEntryChangedFlag || NewEntryInPreparationFlag) // if a save/cancel pending don't permit anything else
4948  {
4949  Utilities->CallLogPop(1688);
4950  return;
4951  }
4952  // find item required - 13 pixels per line of text
4953  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4954  // position changing in AllEntriesTTListBox
4955  if((TopPos + (Y / 13)) >= AllEntriesTTListBox->Items->Count)
4956  {
4958  }
4959  else
4960  {
4961  TTCurrentEntryPtr = TimetableEditVector.begin() + (Y / 13) + TopPos;
4962  }
4963  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4965 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4966  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4967  {
4969  }
4970  else
4971  {
4972  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4973  }
4975  SetLevel1Mode(120);
4976  AllEntriesTTListBox->TopIndex = TopPos; // reset it after SetLevel1Mode to prevent the scroll position changing
4977  Utilities->CallLogPop(1648);
4978  }
4979  catch(const Exception &e)
4980  {
4981  ErrorLog(103, e.Message);
4982  }
4983 }
4984 
4985 // ---------------------------------------------------------------------------
4986 
4987 void __fastcall TInterface::OAListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
4988 {
4989 // Mouseup rather than Mousedown so shows floating label when over selected train
4990  try
4991  {
4992  TrainController->LogEvent("OAListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y) + "," + AnsiString(Button)); // button may be right or left
4993  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OAListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4994  int ScreenPosH, ScreenPosV;
4995  if(Track->RouteFlashFlag || Track->PointFlashFlag) // no action
4996  {
4997  Utilities->CallLogPop(2087);
4998  return;
4999  }
5001  {
5002  Utilities->CallLogPop(2088);
5003  return;
5004  }
5005  int HPos, VPos, TrainID = -1, TrackVectorPosition = -1;
5006  if(!GetTrainIDOrContinuationPosition(0, X, Y, TrainID, TrackVectorPosition))
5007  {
5008  OAListBoxRightMouseButtonDown = false; // so resets when button over blank area
5009  Utilities->CallLogPop(2260);
5010  return;
5011  }
5012  if(Button == mbLeft) // added at v2.7.0 to keep right button for train information
5013  {
5014  HPos = (Track->TrackElementAt(926, TrackVectorPosition).HLoc * 16);
5015  VPos = (Track->TrackElementAt(927, TrackVectorPosition).VLoc * 16);
5016  //if train is already shown on the screen then don't move the viewpoint, if not then display it in the centre
5017  //added at v2.10.0
5018  if(((HPos - (Display->DisplayOffsetH * 16)) >= 0) && ((HPos - (Display->DisplayOffsetH * 16)) < MainScreen->Width) &&
5019  ((VPos - (Display->DisplayOffsetV * 16)) >= 0) && ((VPos - (Display->DisplayOffsetV * 16)) < MainScreen->Height)) // element on screen
5020  {
5021  ScreenPosH = HPos - (Display->DisplayOffsetH * 16);
5022  ScreenPosV = VPos - (Display->DisplayOffsetV * 16);
5023  }
5024  else
5025  {
5026  // set the offsets to display HPos & VPos in the centre of the screen
5027  Display->DisplayOffsetH = (HPos - MainScreen->Width / 2) / 16; // ScreenPosH = HPos - (DisplayOffsetH * 16)
5028  Display->DisplayOffsetV = (VPos - MainScreen->Height / 2) / 16;
5029  ScreenPosH = HPos - (Display->DisplayOffsetH * 16);
5030  ScreenPosV = VPos - (Display->DisplayOffsetV * 16);
5031  }
5032  if(Display->ZoomOutFlag) // panel displays in either zoom mode
5033  {
5034  Display->ZoomOutFlag = false;
5036  }
5037  ClearandRebuildRailway(72); // if was zoomed out this displays the track because until ZoomOutFlag reset PlotOutput plots nothing
5038  TPoint MainScreenPoint(ScreenPosH + 8, ScreenPosV + 8); // new v2.2.0 add 8 to centre pointer in element
5039  TPoint CursPos = MainScreen->ClientToScreen(MainScreenPoint); // accurate funtion to convert from local to global co-ordinates
5040  Mouse->CursorPos = CursPos;
5041  }
5042  else // mbRight, reset OAListBoxRightMouseButtonDown
5043  {
5045  }
5046  Utilities->CallLogPop(2090);
5047  }
5048  catch(const Exception &e)
5049  {
5050  ErrorLog(200, e.Message);
5051  }
5052 }
5053 
5054 // ---------------------------------------------------------------------------
5055 
5056 void __fastcall TInterface::OAListBoxMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
5057 {
5058  try
5059  {
5060  TrainController->LogEvent("OAListBoxMouseDown," + AnsiString(X) + "," + AnsiString(Y));
5061  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OAListBoxMouseDown");
5062  if(Button == mbRight)
5063  {
5065  }
5066  Utilities->CallLogPop(2264);
5067  }
5068  catch(const Exception &e)
5069  {
5070  ErrorLog(220, e.Message);
5071  }
5072 }
5073 
5074 // ---------------------------------------------------------------------------
5075 
5076 bool TInterface::GetTrainIDOrContinuationPosition(int Caller, int X, int Y, int &TrainID, int &TrackVectorPosition)
5077 // returns true if value(s) valid
5078 {
5079  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",GetTrainIDOrContinuationPosition");
5081  // find item required - 13 pixels per line of text
5082  int TopPos = OAListBox->TopIndex;
5083  int OAIndex;
5084  if((TopPos + (Y / 13)) >= OAListBox->Items->Count) // if click beyond end of list ignore
5085  {
5086  Utilities->CallLogPop(2089);
5087  return(false);
5088  }
5089  else
5090  {
5091  OACurrentEntryPtr = TrainController->OpTimeToActMultiMap.begin();
5092  std::advance(OACurrentEntryPtr, ((Y / 13) + TopPos));
5093  }
5094  int TrainIDorTVPos = OACurrentEntryPtr->second.second;
5095  if(TrainIDorTVPos >= 0) // running train, so value is the TrainID
5096  {
5097  if(TrainController->TrainExistsAtIdent(0, TrainIDorTVPos)) // added at v2.4.0 in case train removed but still in OA list as not updated yet
5098  // see LiWinDom error report on Discord 23/04/20. Also needed for click OAListBox before any trains show,
5099  // as notified by Rokas Serys by email on 16/05/20
5100  {
5101  TrainID = TrainIDorTVPos;
5102  TrackVectorPosition = TrainController->TrainVectorAtIdent(43, TrainIDorTVPos).LeadElement;
5103  }
5104  else
5105  {
5106  Utilities->CallLogPop(2155); // if not there then ignore
5107  return(false);
5108  }
5109  }
5110  else // train to enter at a continuation, so value is -TVPos of continuation - 1
5111  {
5112  TrackVectorPosition = -(TrainIDorTVPos + 1);
5113  }
5114  Utilities->CallLogPop(2261);
5115  return(true);
5116 }
5117 
5118 // ---------------------------------------------------------------------------
5119 
5121 {
5122  enum
5123  {
5124  PreStartTime, ActiveSegment, PostEnd
5125  } Segment;
5126  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CompileAllEntriesMemoAndSetPointers");
5127  AllEntriesTTListBox->Clear();
5128  TEVPtr = 0;
5129  TTStartTimePtr = 0;
5130  TTFirstServicePtr = 0;
5131  TTLastServicePtr = 0; // all set to null to begin with
5132  if(TimetableEditVector.empty())
5133  {
5134  TTCurrentEntryPtr = 0;
5135  Utilities->CallLogPop(1681);
5136  return;
5137  }
5138  Segment = PreStartTime;
5139  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
5140  {
5141  if(Segment == PreStartTime) // looking for the start time
5142  {
5143  TDateTime TempTime; // dummy
5144  if(TrainController->CheckTimeValidity(33, *TEVPtr, TempTime))
5145  {
5146  TTStartTimePtr = TEVPtr; // TTStartTimeBox text set in TTHandler
5147  AllEntriesTTListBox->Items->Add("START " + (*TEVPtr).SubString(1, 5));
5148  Segment = ActiveSegment;
5149  continue;
5150  }
5151  else
5152  {
5153  if(*TEVPtr == "")
5154  {
5155  AllEntriesTTListBox->Items->Add("- Blank");
5156  }
5157  else
5158  {
5159  AnsiString CurrentStr = *TEVPtr;
5160  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
5161  {
5162  CurrentStr = CurrentStr.SubString(1, 10); // limit length for LH window
5163  for(int x = 1; x < CurrentStr.Length(); x++)
5164  {
5165  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
5166  {
5167  CurrentStr = CurrentStr.SubString(1, (x - 1));
5168  }
5169  }
5170  }
5171  AllEntriesTTListBox->Items->Add("- " + CurrentStr);
5172  }
5173  continue;
5174  }
5175  }
5176  if(Segment == ActiveSegment)
5177  {
5178  if(*TEVPtr != "")
5179  {
5180  if((*TEVPtr)[1] != '*')
5181  {
5183  ConvertCRLFsToCommas(0, *TEVPtr); // This needed because an entry intended as a service might have skipped the conversion in
5184  // SaveTTEntryButtonClick - see comment in that function
5185  if(TTFirstServicePtr == 0)
5186  {
5188  }
5190  }
5191  AnsiString Entry = *TEVPtr;
5192 
5193 /* dropped at v2.9.1 so comment entries more meaningful, they self truncate to AllEntriesTTListBox width
5194  if(Entry[1] == '*')
5195  {
5196  Entry = "Comment";
5197  }
5198 */
5199  if(Entry[1] != '*') //changed from 'else' at v2.9.1
5200  {
5201  int SCPos = Entry.Pos(';'); // semicolon
5202  int CPos = Entry.Pos(','); // comma
5203  // 5 possibilities: no comma & no semicolon - just text - enter 1st 12 characters
5204  // both, comma before semicolon, i.e text on its own line, semicolon on next line - e.g. service headcode but no
5205  // description - enter the text up to the comma
5206  // both, semicolon before comma, normal - enter text up to the semicolon
5207  // comma & no semicolon, one or more lines of text without any semicolons - enter the text up to the comma
5208  // semicolon & no comma - enter text up to the semicolon
5209  if((CPos == 0) && (SCPos == 0))
5210  {
5211  Entry = Entry.SubString(1, 12);
5212  }
5213  else if((CPos > 0) && (SCPos > 0) && (CPos < SCPos))
5214  {
5215  Entry = Entry.SubString(1, CPos - 1);
5216  }
5217  else if((CPos > 0) && (SCPos > 0) && (CPos > SCPos))
5218  {
5219  Entry = Entry.SubString(1, SCPos - 1);
5220  }
5221  else if((CPos > 0) && (SCPos == 0))
5222  {
5223  Entry = Entry.SubString(1, CPos - 1);
5224  }
5225  else
5226  {
5227  Entry = Entry.SubString(1, SCPos - 1);
5228  }
5229  }
5230  AllEntriesTTListBox->Items->Add(Entry);
5231  continue;
5232  }
5233  else
5234  {
5235  Segment = PostEnd;
5236  AllEntriesTTListBox->Items->Add("END (Blank)");
5237  continue;
5238  }
5239  }
5240  if(Segment == PostEnd)
5241  {
5242  if(*TEVPtr == "")
5243  {
5244  AllEntriesTTListBox->Items->Add("+ Blank");
5245  }
5246  else
5247  {
5248  AnsiString CurrentStr = *TEVPtr;
5249  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
5250  {
5251  CurrentStr = CurrentStr.SubString(1, 10);
5252  for(int x = 1; x < CurrentStr.Length(); x++)
5253  {
5254  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
5255  {
5256  CurrentStr = CurrentStr.SubString(1, (x - 1));
5257  }
5258  }
5259  }
5260  AllEntriesTTListBox->Items->Add("+ " + CurrentStr);
5261  }
5262  continue;
5263  }
5264  }
5265  if(TTStartTimePtr == 0)
5266  {
5267  TTStartTimeBox->Text = "";
5268  }
5269  TTCurrentEntryPtr = TTLastServicePtr; // may well be reset outside this function but need to ensure that it has a valid value on exit, even if it's null
5270  Utilities->CallLogPop(1680);
5271 }
5272 // ---------------------------------------------------------------------------
5273 
5274 void __fastcall TInterface::AZOrderButtonClick(TObject *Sender)
5275 {
5276  try
5277  {
5278  if(TimetableEditVector.empty())
5279  {
5280  return; // should be able to access this if it is but keep in for safety
5281  }
5282  TrainController->LogEvent("AZOrderClick");
5283  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AZOrderClick");
5284  if(AZOrderButton->Caption == AnsiString("A-Z Order"))
5285  {
5286  TTEVPtr SortStart, SortEnd;
5287  UnicodeString MessageStr =
5288  "If you wish to preserve the original order don't save any changes whilst in alphabetical order.\n\n" "To preserve the original order use alphabetical order to find the service required, click it to display it,"
5289  " then revert to the original order where the same service will be displayed and can be changed.";
5290  Application->MessageBox(MessageStr.c_str(), L"Please Note:", MB_OK | MB_ICONWARNING);
5293  SortStart = TimetableEditVector.begin(); // if no start time set sort from beginning
5294  if(TTFirstServicePtr != NULL)
5295  {
5296  SortStart = TTFirstServicePtr;
5297  }
5298  SortEnd = TimetableEditVector.end(); // if no last service set sort to end
5299  if(TTLastServicePtr != NULL)
5300  {
5301  SortEnd = TTLastServicePtr + 1;
5302  }
5303  std::sort(SortStart, SortEnd);
5305  bool CurrentEntryChanged = false;
5306  for(TTimetableEditVector::iterator x = TimetableEditVector.begin(); x < TimetableEditVector.end(); x++)
5307  {
5308  if(TTSelectedEntry == *x)
5309  {
5310  TTCurrentEntryPtr = x;
5311  CurrentEntryChanged = true;
5312  }
5313  }
5314  if(!CurrentEntryChanged)
5315  {
5317  }
5318  AZOrderButton->Caption = AnsiString("Original Order");
5319  AZOrderButton->Hint = AnsiString("Arrange services in original order Toggle with Shift+ Z");
5320  }
5321  else
5322  {
5324  {
5325  UnicodeString MessageStr =
5326  "Reverting to the original order will discard any changes made whilst in alphabetical order.\n\nTo preserve the changes click 'No', then save the timetable or use 'save as' if you wish to keep the original timetable.\n\nDo you wish to proceed?";
5327  int button = Application->MessageBox(MessageStr.c_str(), L"Warning!", MB_YESNO | MB_ICONWARNING);
5328  if(button == IDNO)
5329  {
5330  TimetableChangedFlag = true;
5331  TimetableValidFlag = false;
5333  SetLevel1Mode(135);
5334  Utilities->CallLogPop(2166);
5335  return;
5336  }
5337  }
5341  bool CurrentEntryChanged = false;
5342  for(TTimetableEditVector::iterator x = TimetableEditVector.begin(); x < TimetableEditVector.end(); x++)
5343  {
5344  if(TTSelectedEntry == *x)
5345  {
5346  TTCurrentEntryPtr = x;
5347  CurrentEntryChanged = true;
5348  }
5349  }
5350  if(!CurrentEntryChanged)
5351  {
5353  }
5354  AZOrderButton->Caption = AnsiString("A-Z Order");
5355  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
5356  }
5357  TimetableChangedFlag = true;
5358  TimetableValidFlag = false;
5361  SetLevel1Mode(136);
5362  Utilities->CallLogPop(2165);
5363  }
5364  catch(const Exception &e)
5365  {
5366  ErrorLog(211, e.Message);
5367  }
5368 }
5369 
5370 // ---------------------------------------------------------------------------
5371 
5372 void TInterface::ConvertCRLFsToCommas(int Caller, AnsiString &ConvStr)
5373 {
5374  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertCRLFsToCommas," + ConvStr);
5375  AnsiString OutStr = "";
5376  int x = 1; // AnsiString arrays start at 1
5377 
5378  while(x < ConvStr.Length()) // skip the last character as looking for CRLF pairs, i.e. '\r' followed by '\n'
5379  {
5380  if((ConvStr[x] == '\r') && (ConvStr[x + 1] == '\n'))
5381  {
5382  OutStr += ',';
5383  x++;
5384  x++;
5385  }
5386  else
5387  {
5388  OutStr += ConvStr[x];
5389  x++;
5390  }
5391  }
5392  if(x == ConvStr.Length())
5393  {
5394  OutStr += ConvStr[x]; // add the last character
5395 
5396  }
5397 // strip any excess commas from the end
5398  if(OutStr != "")
5399  {
5400  while(OutStr[OutStr.Length()] == ',')
5401  {
5402  OutStr = OutStr.SubString(1, OutStr.Length() - 1);
5403  if(OutStr == "")
5404  {
5405  break; // if consisted of just commas then without this would fail on range error when becomes a null string
5406  }
5407  }
5408  }
5409  ConvStr = OutStr;
5410  if(ConvStr == "")
5411  {
5412  ConvStr = ','; // don't return a null or will fail, OK to return a comma on its own as will be ignored during ProcessOneTimetableLine
5413  }
5414  // when AllCommas will be true
5415  Utilities->CallLogPop(1846);
5416 }
5417 
5418 // ---------------------------------------------------------------------------
5419 
5421 {
5422 /* CreateEditTTFileName set if a TT file loaded (even if empty), the pointers TTStartTimePtr, TTFirstServicePtr, TTLastServicePtr provide
5423  relevant information - if null then not set. TTCurrentEntryPtr is set to the Entry to be displayed or null if there's no start time or no
5424  entries
5425 */
5426  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TimetableHandler");
5427  PreviousTTEntryButton->Enabled = false;
5428  NextTTEntryButton->Enabled = false;
5429  AddMinsButton->Enabled = false;
5430  SubMinsButton->Enabled = false;
5431  CopyTTEntryButton->Enabled = false;
5432  CutTTEntryButton->Enabled = false;
5433  PasteTTEntryButton->Enabled = false;
5434  DeleteTTEntryButton->Enabled = false;
5435  SaveTTEntryButton->Enabled = false;
5436  SaveTTButton->Enabled = false;
5437  SaveTTAsButton->Enabled = false;
5438  ValidateTimetableButton->Enabled = false;
5439  AZOrderButton->Enabled = false;
5440  TTServiceSyntaxCheckButton->Enabled = false;
5441  NewTTEntryButton->Enabled = false;
5442  MoveTTEntryUpButton->Enabled = false;
5443  MoveTTEntryDownButton->Enabled = false;
5444  CancelTTEntryButton->Enabled = false;
5445  RestoreTTButton->Enabled = false;
5446  ExportTTButton->Enabled = false;
5447  ConflictAnalysisButton->Enabled = false;
5448  ExitTTModeButton->Enabled = true;
5449 
5451  {
5452  AZOrderButton->Enabled = true;
5453  }
5455  {
5456  TimetableValidFlag = false; // should always be the case anyway but include here to be sure
5457 
5458  }
5459  if(CreateEditTTFileName == "")
5460  {
5461  TimetableNameLabel->Caption = "Creating new timetable: not yet saved";
5462  }
5463  else
5464  {
5465  TimetableNameLabel->Caption = "Editing timetable: " + CreateEditTTTitle;
5466  }
5467  if(TTStartTimePtr != 0) // Null means start time not yet set
5468  {
5469  TTStartTimeBox->Text = (*TTStartTimePtr).SubString(1, 5); // 1st 5 chars = time if validity check OK
5470  }
5471 // start time now set & displayed
5472 
5474  {
5475  InfoPanel->Visible = true;
5476  InfoPanel->Caption = "Select option or change entry";
5477  if(RailwayTitle != "")
5478  {
5479  ShowHideTTButton->Enabled = true;
5480  }
5481  else
5482  {
5483  ShowHideTTButton->Enabled = false;
5484  }
5485  ExitTTModeButton->Enabled = true;
5486  AllEntriesTTListBox->Enabled = true;
5487  AnsiString AnsiAddSubText(AddSubMinsBox->Text);
5488  if((AnsiAddSubText != "") && AreAnyTimesInCurrentEntry())
5489  {
5490  bool ValidFlag = true;
5491  for(int x = 1; x <= AnsiAddSubText.Length(); x++)
5492  {
5493  if((AnsiAddSubText[x] > '9') || (AnsiAddSubText[x] < '0'))
5494  {
5495  ValidFlag = false;
5496  break;
5497  }
5498  }
5499  if(ValidFlag)
5500  {
5501  if(AnsiAddSubText.ToInt() != 0)
5502  {
5503  AddMinsButton->Enabled = true;
5504  SubMinsButton->Enabled = true;
5505  }
5506  }
5507  }
5509  {
5510  RestoreTTButton->Enabled = true;
5511  }
5513  {
5514  // Need !TimetableChangedFlag because the changed TT must be saved before validation - it's the TT file that is checked
5515  // so if it is changed but not saved, the 'correct' file will check OK but the changed TT may well not be valid
5516  ValidateTimetableButton->Enabled = true;
5517  }
5519  {
5520  ExportTTButton->Enabled = true;
5521  ConflictAnalysisButton->Enabled = true;
5522  }
5523  if(TTCurrentEntryPtr != 0)
5524  {
5525  CopyTTEntryButton->Enabled = true;
5526  CutTTEntryButton->Enabled = true;
5527  DeleteTTEntryButton->Enabled = true;
5528  }
5529  if((TimetableChangedFlag) && !TimetableEditVector.empty())
5530  {
5531  SaveTTButton->Enabled = true;
5532  }
5533  if(!TimetableEditVector.empty())
5534  {
5535  SaveTTAsButton->Enabled = true;
5536  }
5538  {
5539  NewTTEntryButton->Enabled = true;
5540  }
5541  if((TTCurrentEntryPtr > 0) && !TimetableEditVector.empty())
5542  {
5543  if((TimetableEditVector.end() - 1) > TTCurrentEntryPtr)
5544  {
5545  NextTTEntryButton->Enabled = true;
5546  MoveTTEntryDownButton->Enabled = true;
5547  }
5549  {
5550  PreviousTTEntryButton->Enabled = true;
5551  MoveTTEntryUpButton->Enabled = true;
5552  }
5553  }
5554  if(TTCurrentEntryPtr > 0)
5555  {
5556  if(*TTCurrentEntryPtr != "")
5557  {
5559  {
5560  TTServiceSyntaxCheckButton->Enabled = true;
5561  }
5562  }
5563  }
5564  if(CopiedEntryFlag)
5565  {
5566  PasteTTEntryButton->Enabled = true;
5567  }
5568  OneEntryTimetableMemo->Clear(); // don't clear if Entry changed
5569  if(TTCurrentEntryPtr > 0)
5570  {
5571 // if(*TTCurrentEntryPtr != "") leave this out or fails to highlight blank line entries
5573  {
5574  bool ServiceEntry = true;
5575  DisplayOneTTLineInPanel(0, *TTCurrentEntryPtr, ServiceEntry);
5576  }
5577  else
5578  {
5579  bool ServiceEntry = false;
5580  DisplayOneTTLineInPanel(1, *TTCurrentEntryPtr, ServiceEntry);
5581  }
5582  }
5583  }
5584  else
5585  {
5586  CancelTTEntryButton->Enabled = true;
5587  SaveTTEntryButton->Enabled = true;
5588  ShowHideTTButton->Enabled = false;
5589  ExitTTModeButton->Enabled = false;
5590  AllEntriesTTListBox->Enabled = false; // to stop entries being selected
5591  InfoPanel->Caption = "Add or change entry then save it, or cancel";
5592  InfoPanel->Visible = true;
5593  }
5594  Utilities->CallLogPop(1600);
5595 }
5596 
5597 // ---------------------------------------------------------------------------
5598 void TInterface::DisplayOneTTLineInPanel(int Caller, AnsiString Data, bool ServiceEntry)
5599 {
5600  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DisplayOneTTLineInPanel," + Data + ", " +
5601  AnsiString((short)ServiceEntry));
5602  OneEntryTimetableMemo->Clear();
5603  if(ServiceEntry)
5604  {
5605  TrainController->StripSpaces(1, Data);
5606  while(true)
5607  {
5608  int CommaPos = Data.Pos(',');
5609  if((CommaPos == 0) && (Data != ""))
5610  {
5611  CommaPos = Data.Length() + 1;
5612  }
5613  OneEntryTimetableMemo->Lines->Add(Data.SubString(1, CommaPos - 1));
5614  if(Data.Length() <= CommaPos)
5615  {
5616  break;
5617  }
5618  Data = Data.SubString(CommaPos + 1, Data.Length() - CommaPos);
5619  }
5620  }
5621  else
5622  {
5623  OneEntryTimetableMemo->Text = Data;
5624  }
5625  int TotalLines = OneEntryTimetableMemo->Lines->Count; // remove excess lines at bottom
5626 
5627  while((OneEntryTimetableMemo->Lines->Strings[TotalLines - 1] == "") || (OneEntryTimetableMemo->Lines->Strings[TotalLines - 1] == "\r\n"))
5628  {
5629  OneEntryTimetableMemo->Lines->Delete(TotalLines - 1);
5630  TotalLines--;
5631  if(TotalLines < 1)
5632  {
5633  break;
5634  }
5635  }
5636  OneEntryTimetableMemo->HideSelection = true;
5637  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
5638  OneEntryTimetableMemo->SelLength = 0;
5640  Utilities->CallLogPop(1602);
5641 }
5642 // ---------------------------------------------------------------------------
5643 
5644 void TInterface::HighlightOneEntryInAllEntriesTTListBox(int Caller, int Position)
5645 {
5646  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",HighlightOneEntryInAllEntriesTTListBox," + AnsiString(Position));
5647  if(TimetableEditVector.empty() || (AllEntriesTTListBox->Items->Count == 0))
5648  {
5649  HighlightPanel->Top = 32;
5650  HighlightPanel->Caption = "";
5651  HighlightPanel->Width = 100;
5652  HighlightPanel->Visible = false;
5653  }
5654  else
5655  {
5656  AnsiString CurrentStr = AllEntriesTTListBox->Items->Strings[Position];
5657  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
5658  {
5659  for(int x = 1; x < CurrentStr.Length(); x++)
5660  {
5661  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
5662  {
5663  CurrentStr = CurrentStr.SubString(1, (x - 1));
5664  }
5665  }
5666  }
5667  HighlightPanel->Top = 32 + (Position * 13) - (AllEntriesTTListBox->TopIndex * 13);
5668  if(HighlightPanel->Top < 32)
5669  {
5670  HighlightPanel->Visible = false;
5671  }
5672  else
5673  {
5674  HighlightPanel->Visible = true; // doesn't matter if goes off the bottom as it becomes invisible as then it's off its parent panel
5675  }
5676  HighlightPanel->Caption = CurrentStr;
5677  if(AllEntriesTTListBox->Items->Count > 47) // because the scrollbar will be present
5678  {
5679  HighlightPanel->Width = 82;
5680  }
5681  else
5682  {
5683  HighlightPanel->Width = 100;
5684  }
5685  }
5686  Utilities->CallLogPop(1709);
5687 }
5688 
5689 // ---------------------------------------------------------------------------
5691 {
5692  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == ""))
5693  {
5694  return(false);
5695  }
5696  TDateTime DummyTime;
5697  bool TimesPresent = false;
5698 
5699  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
5700  {
5701  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
5702  {
5703  if(TrainController->CheckTimeValidity(20, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
5704  {
5705  TimesPresent = true;
5706  break;
5707  }
5708  }
5709  if(TimesPresent)
5710  {
5711  break;
5712  }
5713  }
5714  return(TimesPresent);
5715 }
5716 
5717 // ---------------------------------------------------------------------------
5718 // end of Timetable editing functions
5719 // ---------------------------------------------------------------------------
5720 void __fastcall TInterface::ExitMenuItemClick(TObject *Sender)
5721 {
5722  try
5723  {
5724  TrainController->LogEvent("ExitMenuItemClick");
5725  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitMenuItemClick");
5726 /* Dropped at v2.9.1 as serves no apparent purpose
5727  if(!FileChangedFlag && !(Track->IsTrackFinished()) && (EveryPrefDir->PrefDirSize() > 0))
5728  {
5729  UnicodeString MessageStr =
5730  "Note that leaving the track unlinked will cause preferred directions to be lost on reloading. Prevent by linking the track then resaving. Do you still wish to exit?";
5731  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
5732  if(button == IDNO)
5733  {
5734  Utilities->CallLogPop(1711);
5735  return;
5736  }
5737  }
5738 */
5739  if(FileChangedFlag)
5740  {
5741  UnicodeString MessageStr = "The railway has changed, exit without saving?";
5742  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
5743  if(button == IDNO)
5744  {
5745  Utilities->CallLogPop(1180);
5746  return;
5747  }
5748  }
5749  if((TempTTFileName != "") && FileExists(TempTTFileName))
5750  {
5751  DeleteFile(TempTTFileName);
5752  }
5753  Utilities->CallLogPop(1181);
5754  Application->Terminate();
5755  }
5756  catch(const Exception &e)
5757  {
5758  ErrorLog(140, e.Message);
5759  }
5760 }
5761 // ---------------------------------------------------------------------------
5762 
5763 void __fastcall TInterface::TrackInfoOnOffMenuItemClick(TObject *Sender)
5764 {
5765  try
5766  {
5767  TrainController->LogEvent("TrackInfoOnOffMenuItemClick");
5768  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrackInfoOnOffMenuItemClick");
5769  if(TrackInfoOnOffMenuItem->Caption == "Show")
5770  {
5771  TrackInfoOnOffMenuItem->Caption = "Hide";
5772  }
5773  else
5774  {
5775  TrackInfoOnOffMenuItem->Caption = "Show";
5776  }
5777  Utilities->CallLogPop(1183);
5778  }
5779  catch(const Exception &e)
5780  {
5781  ErrorLog(173, e.Message);
5782  }
5783 }
5784 // ---------------------------------------------------------------------------
5785 
5786 void __fastcall TInterface::TrainStatusInfoOnOffMenuItemClick(TObject *Sender)
5787 {
5788  try
5789  {
5790  TrainController->LogEvent("TrainStatusInfoOnOffMenuItemClick");
5791  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrainStatusInfoOnOffMenuItemClick");
5792  if(TrainStatusInfoOnOffMenuItem->Caption == "Show Status")
5793  {
5794  TrainStatusInfoOnOffMenuItem->Caption = "Hide Status";
5795  }
5796  else
5797  {
5798  TrainStatusInfoOnOffMenuItem->Caption = "Show Status";
5799  }
5800  Utilities->CallLogPop(1184);
5801  }
5802  catch(const Exception &e)
5803  {
5804  ErrorLog(141, e.Message);
5805  }
5806 }
5807 
5808 // ---------------------------------------------------------------------------
5809 void __fastcall TInterface::TrainTTInfoOnOffMenuItemClick(TObject *Sender)
5810 {
5811  try
5812  {
5813  TrainController->LogEvent("TrainTTInfoOnOffMenuItemClick");
5814  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrainTTInfoOnOffMenuItemClick");
5815  if(TrainTTInfoOnOffMenuItem->Caption == "Show Timetable")
5816  {
5817  TrainTTInfoOnOffMenuItem->Caption = "Hide Timetable";
5818  }
5819  else
5820  {
5821  TrainTTInfoOnOffMenuItem->Caption = "Show Timetable";
5822  }
5823  Utilities->CallLogPop(1185);
5824  }
5825  catch(const Exception &e)
5826  {
5827  ErrorLog(142, e.Message);
5828  }
5829 }
5830 
5831 // ---------------------------------------------------------------------------
5832 // Dragging Functions
5833 // ---------------------------------------------------------------------------
5834 void __fastcall TInterface::AcceptDragging(TObject *Sender, TObject *Source, int X, int Y, TDragState State, bool &Accept)
5835 {
5836 // allow in zoom out mode
5837  try
5838  {
5839 // TrainController->LogEvent("AcceptDragging"); drop this, have too many
5840  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AcceptDragging");
5841  if((Source == PerformancePanel) || (Source == PerformancePanelLabel) || (Source == PerformanceLogBox))
5842  {
5843  Accept = true;
5844  int PPLeft = PerformancePanel->Left;
5845  int PPTop = PerformancePanel->Left;
5846 
5847  PPLeft = Mouse->CursorPos.x - PerformancePanelDragStartX;
5848  PPTop = Mouse->CursorPos.y - PerformancePanelDragStartY;
5849  if((PPLeft + PerformancePanel->Width) < 32)
5850  {
5851  PPLeft = 32 - PerformancePanel->Width;
5852  }
5853  if(PPLeft > (MainScreen->Left + MainScreen->Width))
5854  {
5855  PPLeft = MainScreen->Left + MainScreen->Width;
5856  }
5857  if((PPTop + PerformancePanel->Height) < MainScreen->Top)
5858  {
5859  PPTop = MainScreen->Top - PerformancePanel->Height;
5860  }
5861  if(PPTop > (MainScreen->Top + MainScreen->Height - 20))
5862  {
5863  PPTop = MainScreen->Top + MainScreen->Height - 20;
5864  }
5865  PerformancePanel->Left = PPLeft;
5866  PerformancePanel->Top = PPTop;
5867  }
5868  else if((Source == OperatorActionPanel) || (Source == OAPanelLabel))
5869  // not the listbox because that used for selecting trains
5870  {
5871  Accept = true;
5872  int OALeft = OperatorActionPanel->Left;
5873  int OATop = OperatorActionPanel->Left;
5874 
5875  OALeft = Mouse->CursorPos.x - OperatorActionPanelDragStartX;
5876  OATop = Mouse->CursorPos.y - OperatorActionPanelDragStartY;
5877  if((OALeft + OperatorActionPanel->Width) < 32)
5878  {
5879  OALeft = 32 - OperatorActionPanel->Width;
5880  }
5881  if(OALeft > (MainScreen->Left + MainScreen->Width))
5882  {
5883  OALeft = MainScreen->Left + MainScreen->Width;
5884  }
5885  if((OATop + OperatorActionPanel->Height) < MainScreen->Top)
5886  {
5887  OATop = MainScreen->Top - OperatorActionPanel->Height;
5888  }
5889  if(OATop > (MainScreen->Top + MainScreen->Height - 20))
5890  {
5891  OATop = MainScreen->Top + MainScreen->Height - 20;
5892  }
5893  OperatorActionPanel->Left = OALeft;
5894  OperatorActionPanel->Top = OATop;
5895  }
5896  else
5897  {
5898  Accept = false;
5899  }
5900  Utilities->CallLogPop(1186);
5901  }
5902  catch(const Exception &e)
5903  {
5904  ErrorLog(143, e.Message);
5905  }
5906 }
5907 
5908 // ---------------------------------------------------------------------------
5909 void __fastcall TInterface::PerformancePanelStartDrag(TObject *Sender, TDragObject *&DragObject)
5910 {
5911 // allow in zoom out mode
5912  try
5913  {
5914  TrainController->LogEvent("PerformancePanelStartDrag");
5915  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformancePanelStartDrag");
5916  PerformancePanelDragStartX = Mouse->CursorPos.x - PerformancePanel->Left;
5917  PerformancePanelDragStartY = Mouse->CursorPos.y - PerformancePanel->Top;
5918  Utilities->CallLogPop(1187);
5919  }
5920  catch(const Exception &e)
5921  {
5922  ErrorLog(144, e.Message);
5923  }
5924 }
5925 // ---------------------------------------------------------------------------
5926 
5927 void __fastcall TInterface::OperatorActionPanelStartDrag(TObject *Sender, TDragObject *&DragObject) // new v2.2.0
5928 
5929 {
5930 // allow in zoom out mode
5931  try
5932  {
5933  TrainController->LogEvent("OperatorActionPanelStartDrag");
5934  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperatorActionPanelStartDrag");
5935  OperatorActionPanelDragStartX = Mouse->CursorPos.x - OperatorActionPanel->Left;
5936  OperatorActionPanelDragStartY = Mouse->CursorPos.y - OperatorActionPanel->Top;
5937  Utilities->CallLogPop(2091);
5938  }
5939  catch(const Exception &e)
5940  {
5941  ErrorLog(201, e.Message);
5942  }
5943 }
5944 
5945 // ---------------------------------------------------------------------------
5946 // Mouse Functions
5947 // ---------------------------------------------------------------------------
5948 void __fastcall TInterface::MainScreenMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
5949 // caller function - stops master clock
5950 {
5951 // have to allow in zoom out mode
5952  try
5953  {
5954  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseDown," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
5955  bool ClockState = Utilities->Clock2Stopped;
5956  Utilities->Clock2Stopped = true;
5957 
5958  RestoreFocusPanel->Enabled = true; // these added at v2.0.0 to restore navigation keys to move screen when a panel had focus
5959  RestoreFocusPanel->Visible = true; // because then these buttons just cycled through the panel buttons. Added in place of the
5960  RestoreFocusPanel->SetFocus(); // section in ClockTimer2 where focus restored every clock cycle, because then the help screen
5961  RestoreFocusPanel->Visible = false; // was hidden. At least now help is only hidden when the screen clicked, which is normal
5962  RestoreFocusPanel->Enabled = false; // behaviour, and can tell user that can restore navigation keys just by clicking the screen
5963  MMoveTrackSelFlag = false;
5964  MMovePrefDirSelFlag = false;
5968 
5970  {
5971  if(!Display->ZoomOutFlag)
5972  {
5973  MainScreenMouseDown2(0, Button, Shift, X, Y);
5974  }
5975  else
5976  {
5977  MainScreenMouseDown3(0, Button, Shift, X, Y);
5978  }
5979  }
5980  Utilities->Clock2Stopped = ClockState;
5981  Utilities->CallLogPop(33);
5982  }
5983  catch(const Exception &e)
5984  {
5985  ErrorLog(19, e.Message);
5986  }
5987 }
5988 
5989 // ---------------------------------------------------------------------------
5990 void TInterface::MainScreenMouseDown2(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
5991 {
5992  try
5993  {
5994  TrainController->LogEvent("MainScreenMouseDown2," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
5995  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MainScreenMouseDown2," + AnsiString(Button) + "," + AnsiString(X) +
5996  "," + AnsiString(Y));
5997  // unplot GapFlash graphics if plotted & cancel gap flashing if left mouse button pressed (so can move display with right mouse button)
5998  // but not in ZoomOut mode - so can switch between modes & keep gaps flashing
5999  if(Track->GapFlashFlag && !Display->ZoomOutFlag && (Button == mbLeft))
6000  {
6003  Track->GapFlashFlag = false;
6004  }
6005  int HLoc, VLoc;
6006  Track->GetTrackLocsFromScreenPos(1, HLoc, VLoc, X, Y);
6007  int NoOffsetX, NoOffsetY;
6008  Track->GetTruePositionsFromScreenPos(0, NoOffsetX, NoOffsetY, X, Y);
6009  if(Button == mbRight) // track, PrefDir or text erase, PrefDir/route truncate, or take signaller control of train
6010  {
6011  // this routine new at v2.1.0. Allows railway moving for zoom-in mode when no element at HLoc & VLoc
6012  int Dummy; // unused in next function
6013  AnsiString Text = ""; // needed for TextFound but not used
6014  if(!Track->TrackElementPresentAtHV(0, HLoc, VLoc) && !Track->InactiveTrackElementPresentAtHV(0, HLoc, VLoc) && !Track->UserGraphicPresentAtHV(0, X,
6015  Y, Dummy) && !TextHandler->TextFound(0, X + (Display->DisplayOffsetH * 16), Y + (Display->DisplayOffsetV * 16), Text))
6016  {
6019  WholeRailwayMoving = true;
6020  Screen->Cursor = TCursor(-22); // Four arrows;
6021  }
6022 
6023  else if(Level2TrackMode == AddText)
6024  {
6025  TrainController->LogEvent("mbRight + AddText");
6026 // ResetChangedFileDataAndCaption(, true); moved from here after 2.7.0 in case no changes made
6027  if(TextHandler->TextFound(1, NoOffsetX, NoOffsetY, Text))
6028  {
6029  if(TextHandler->TextErase(0, NoOffsetX, NoOffsetY, Text)) // erase text in vector
6030  {
6031  ResetChangedFileDataAndCaption(2, true); // moved to here after 2.7.0
6033  if(NoRailway())
6034  {
6035  EditMenu->Enabled = false;
6036  }
6037  else
6038  {
6039  EditMenu->Enabled = true;
6040  }
6041  }
6042  }
6043  SetLevel2TrackMode(57); // to remove 'move text' if last text item removed
6044  Utilities->CallLogPop(34);
6045  return;
6046  }
6047  else if(Level2TrackMode == AddGraphic)
6048  {
6049  TrainController->LogEvent("mbRight + AddGraphic");
6050  if(Track->UserGraphicVector.empty()) // no user graphics
6051  {
6052  Utilities->CallLogPop(2180);
6053  return;
6054  }
6055  int UGIVecPos;
6056  if(Track->UserGraphicPresentAtHV(1, X, Y, UGIVecPos))
6057  {
6058  Track->UserGraphicVector.erase(Track->UserGraphicVector.begin() + UGIVecPos);
6060  if(NoRailway())
6061  {
6062  EditMenu->Enabled = false;
6063  }
6064  else
6065  {
6066  EditMenu->Enabled = true;
6067  }
6068  }
6069  Utilities->CallLogPop(2181);
6070  return;
6071  }
6072 
6073  else if(Level2TrackMode == AddTrack)
6074  {
6075  TrainController->LogEvent("mbRight + AddTrack");
6076  bool TrackEraseSuccessfulFlag;
6077  int ErasedTrackVectorPosition;
6078  Screen->Cursor = TCursor(-11); // Hourglass;
6079  Track->EraseTrackElement(1, HLoc, VLoc, ErasedTrackVectorPosition, TrackEraseSuccessfulFlag, true);
6080  if(TrackEraseSuccessfulFlag)
6081  {
6082  if(ErasedTrackVectorPosition > -1) //may have been an inactive element
6083  {
6084  EveryPrefDir->RealignAfterTrackErase(0, ErasedTrackVectorPosition);
6085  }
6088  ClearandRebuildRailway(5); // to ensure location named elements plotted correctly & replot the grid if required
6089  SetGapsButton->Enabled = false; // if conditions have changed need to reset buttons, best not calling SetLevel2TrackMode as that
6090  TrackOKButton->Enabled = false; // calls Clearand.. if gridflag set & takes a long time
6091  if(Track->GapsUnset(1))
6092  {
6093  SetGapsButton->Enabled = true;
6094  }
6095  // only enable if there are gaps still to be set (returns false for no track)
6096  else
6097  {
6098  if(!(Track->NoActiveTrack(0)) && !(Track->IsTrackFinished()))
6099  {
6100  TrackOKButton->Enabled = true;
6101  }
6102  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
6103  }
6104  if(!(Track->IsTrackFinished())) // can only set lengths for several elements together if TrackFinished
6105  {
6106  SetLengthsButton->Enabled = false;
6107  }
6108 // if(NoRailway()) dropped at v2.6.0 to allow edits during AddTrack
6109 // {
6110 // EditMenu->Enabled = false;
6111 // }
6112 // else
6113  EditMenu->Enabled = true;
6114  }
6115  Screen->Cursor = TCursor(-2); // Arrow
6116  Utilities->CallLogPop(35);
6117  return;
6118  }
6119  else if(Level2TrackMode == DistanceContinuing) // new for extended distances (similar to PrefDirContinuing)
6120  {
6121  TrainController->LogEvent("mbRight + DistanceContinuing");
6122 // ResetChangedFileDataAndCaption(, true); dropped after 2.7.0 as may only be checking existing distances/speeds. Moved to button clicks in TrackLengthPanel
6123  bool LeadingPointsAtLastElement = false;
6124  if(ConstructPrefDir->GetPrefDirTruncateElement(0, HLoc, VLoc))
6125  {
6126  if(ConstructPrefDir->PrefDirSize() == 0)
6127  {
6129  SetLevel1Mode(64);
6131  SetLevel2TrackMode(51); // calls ClearandRebuildRailway to show length erased & sets back to start
6132  Utilities->CallLogPop(1526);
6133  return;
6134  }
6137  ConstructPrefDir->CalcDistanceAndSpeed(0, OverallDistance, OverallSpeedLimit, LeadingPointsAtLastElement);
6138  if(!LeadingPointsAtLastElement)
6139  {
6140  TrackLengthPanel->Visible = true;
6141  TrackLengthPanel->SetFocus();
6142  InfoPanel->Visible = true;
6143  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
6144  RestoreAllDefaultLengthsButton->Enabled = true;
6145  ResetDefaultLengthButton->Enabled = true;
6146  LengthOKButton->Enabled = true;
6147  DistanceBox->Text = AnsiString(OverallDistance);
6148  if(OverallSpeedLimit > -1)
6149  {
6150  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
6151  }
6152  else
6153  {
6154  SpeedLimitBox->Text = "Mixed";
6155  }
6156  }
6157  else
6158  {
6159  TrackLengthPanel->Visible = true;
6160  TrackLengthPanel->SetFocus();
6161  InfoPanel->Visible = true;
6162  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Can't end on leading points, continue or truncate";
6163  RestoreAllDefaultLengthsButton->Enabled = false;
6164  ResetDefaultLengthButton->Enabled = false;
6165  LengthOKButton->Enabled = false;
6166  }
6168  }
6169  Utilities->CallLogPop(36);
6170  return;
6171  }
6172 
6173  else if(Level2PrefDirMode == PrefDirContinuing) // truncate
6174  {
6175  TrainController->LogEvent("mbRight + PrefDirContinuing");
6176 // ResetChangedFileDataAndCaption(, false); moved to later after 2.7.0 as may not change anything
6177 // RlyFile = false; - don't alter this just for PrefDir changes
6178  if(ConstructPrefDir->GetPrefDirTruncateElement(1, HLoc, VLoc))
6179  {
6180  if(ConstructPrefDir->PrefDirSize() == 0)
6181  {
6183  SetLevel1Mode(14); // all PrefDir truncated
6184  Utilities->CallLogPop(37);
6185  return;
6186  }
6188  ResetChangedFileDataAndCaption(5, false); // moved to here after 2.7.0
6189  }
6191  SetLevel2PrefDirMode(0); // calls ClearandRebuildRailway to show length erased & sets back to start
6192  Utilities->CallLogPop(38);
6193  return;
6194  }
6195 
6196  else if((Level1Mode == PrefDirMode) && (Level2PrefDirMode != PrefDirContinuing) && (Level2PrefDirMode != PrefDirSelecting)) // delete element
6197  {
6198  TrainController->LogEvent("mbRight + != PrefDirContinuing");
6200 // RlyFile = false; - don't alter this just for PrefDir changes
6203  SetLevel1Mode(15); // calls ClearandRebuildRailway to show length erased & sets back to start
6204  Utilities->CallLogPop(39);
6205  return;
6206  }
6207 
6208  else if((Level2OperMode == Operating) || (Level2OperMode == PreStart)) // disallow when paused, but allow some parts in prestart
6209  {
6210  TrainController->LogEvent("mbRight + OperMode");
6211  bool FoundFlag;
6212  int VecPos = Track->GetVectorPositionFromTrackMap(1, HLoc, VLoc, FoundFlag);
6213  if(FoundFlag && (Level2OperMode != PreStart)) // disallow signaller control in PreStart
6214  {
6216  // signaller control of train
6217  if(SelectedTrainID > -1)
6218  {
6221  if((Train.LeadElement == -1) || (Track->TrackElementAt(788, Train.LeadElement).Conn[Train.LeadExitPos] == -1))
6222  {
6223  if(Train.TrainMode == Signaller)
6224  {
6226  }
6227  }
6228  if((Train.Stopped()) || (Train.TrainFailed && !(Train.TrainMode == Signaller)) ||
6230  !Train.StepForwardFlag))
6231  // don't allow signaller popup menu in timetable mode unless stopped,
6232  // or when coming to a stop or leaving at a continuation when under signaller control
6233  // or when failed
6234  {
6235  // don't allow selection if another stopped train at a bridge position
6236  if(Track->TrackElementAt(630, VecPos).TrackType == Bridge)
6237  {
6238  int TrainID01 = Track->TrackElementAt(631, VecPos).TrainIDOnBridgeTrackPos01;
6239  int TrainID23 = Track->TrackElementAt(632, VecPos).TrainIDOnBridgeTrackPos23;
6240  if((TrainID01 > -1) && (TrainID23 > -1))
6241  {
6242  TrainController->StopTTClockMessage(0, "Can't select a train at a bridge when another train is at the same bridge");
6243  Utilities->CallLogPop(1103);
6244  return;
6245  }
6246  }
6247  if(Train.TrainMode == Timetable)
6248  {
6249  TakeSignallerControlMenuItem->Enabled = true;
6250  TimetableControlMenuItem->Enabled = false;
6251  ChangeDirectionMenuItem->Enabled = false;
6252  MoveForwardsMenuItem->Enabled = false;
6253  SignallerJoinedByMenuItem->Enabled = false;
6254  RepairFailedTrainMenuItem->Enabled = false;
6255  StepForwardMenuItem->Enabled = false;
6256  RemoveTrainMenuItem->Enabled = false;
6257  PassRedSignalMenuItem->Enabled = false;
6258  SignallerControlStopMenuItem->Enabled = false;
6259  }
6260  else // signaller mode
6261  {
6262  TakeSignallerControlMenuItem->Enabled = false;
6263  if((Train.Crashed) || (Train.Derailed))
6264  {
6265  TimetableControlMenuItem->Enabled = false;
6266  ChangeDirectionMenuItem->Enabled = false;
6267  MoveForwardsMenuItem->Enabled = false;
6268  SignallerJoinedByMenuItem->Enabled = false;
6269  RepairFailedTrainMenuItem->Enabled = false;
6270  StepForwardMenuItem->Enabled = false;
6271  PassRedSignalMenuItem->Enabled = false;
6272  SignallerControlStopMenuItem->Enabled = false;
6273  RemoveTrainMenuItem->Enabled = true;
6274  }
6275  else if(Train.Stopped())
6276  {
6277  if(Train.TimetableFinished)
6278  {
6279  TimetableControlMenuItem->Enabled = false;
6280  }
6281  else
6282  {
6283  if(Train.RestoreTimetableLocation == "") // en route
6284  {
6285  TimetableControlMenuItem->Enabled = true;
6286  }
6287  else
6288  {
6289  // obtain train location & check if OK for restoration of tt control
6290  AnsiString LocName = "";
6291  if(Train.LeadElement > -1)
6292  {
6293  LocName = Track->TrackElementAt(802, Train.LeadElement).ActiveTrackElementName;
6294  }
6295  if((LocName == "") && (Train.MidElement > -1))
6296  {
6297  LocName = Track->TrackElementAt(803, Train.MidElement).ActiveTrackElementName;
6298  }
6299  if(Train.RestoreTimetableLocation == LocName)
6300  {
6301  TimetableControlMenuItem->Enabled = true;
6302  }
6303  else
6304  {
6305  TimetableControlMenuItem->Enabled = false;
6306  }
6307  }
6308  }
6309 // don't allow ChangeDirection if lead or mid elements (but not lag or next) -1, or lead, mid, lag or next elements continuations
6310  ChangeDirectionMenuItem->Enabled = true;
6311  if(Train.LeadElement > -1)
6312  {
6314  {
6315  ChangeDirectionMenuItem->Enabled = false;
6316  }
6317  if(Track->TrackElementAt(791, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
6318  {
6319  if(Track->TrackElementAt(792, (Track->TrackElementAt(793, Train.LeadElement).Conn[Train.LeadExitPos]))
6320  .TrackType == Continuation)
6321  {
6322  ChangeDirectionMenuItem->Enabled = false;
6323  }
6324  }
6325  }
6326  else
6327  {
6328  ChangeDirectionMenuItem->Enabled = false;
6329  }
6330  if(Train.MidElement > -1)
6331  {
6333  {
6334  ChangeDirectionMenuItem->Enabled = false;
6335  }
6336  }
6337  else
6338  {
6339  ChangeDirectionMenuItem->Enabled = false;
6340  }
6341  if(Train.LagElement > -1)
6342  {
6344  {
6345  ChangeDirectionMenuItem->Enabled = false;
6346  }
6347  }
6348  RemoveTrainMenuItem->Enabled = true;
6349  SignallerControlStopMenuItem->Enabled = false;
6350  SignallerJoinedByMenuItem->Enabled = false;
6351  RepairFailedTrainMenuItem->Enabled = false;
6352  StepForwardMenuItem->Enabled = false;
6353  MoveForwardsMenuItem->Enabled = false;
6354  PassRedSignalMenuItem->Enabled = false;
6355  if(Train.AbleToMove(0))
6356  {
6357  MoveForwardsMenuItem->Enabled = true;
6359  {
6360  StepForwardMenuItem->Enabled = true; // added 'if' condition for v1.3.2 due to Carwyn Thomas error,
6361  }
6362  } // fails on trying to calc AutoSig time delay for resetting signals
6363 
6364  if(Train.AbleToMoveButForSignal(0)) // may not be in AutoSigs route but disallow anyway as not needed at continuation
6365  {
6366  PassRedSignalMenuItem->Enabled = true;
6367  StepForwardMenuItem->Enabled = true;
6368  }
6369  TTrain *AdjacentTrain;
6370  if(Train.IsThereAnAdjacentTrain(0, AdjacentTrain))
6371  {
6372  SignallerJoinedByMenuItem->Enabled = true;
6373  }
6374  if(Train.TrainFailed)
6375  {
6376  RepairFailedTrainMenuItem->Enabled = true;
6377  }
6378  }
6379  else // train moving under signaller control - only permit restoration of TT control when stopped as could be in
6380  // mid move, & SetTrainMovementValues only intended to be called when stopped
6381  {
6382  TimetableControlMenuItem->Enabled = false;
6383  ChangeDirectionMenuItem->Enabled = false;
6384  RemoveTrainMenuItem->Enabled = false;
6385  MoveForwardsMenuItem->Enabled = false;
6386  SignallerJoinedByMenuItem->Enabled = false;
6387  RepairFailedTrainMenuItem->Enabled = false;
6388  PassRedSignalMenuItem->Enabled = false;
6389  StepForwardMenuItem->Enabled = false;
6390  SignallerControlStopMenuItem->Enabled = true;
6391  }
6392  }
6393  TrainHeadCodeMenuItem->Caption = Train.HeadCode + ":";
6394  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
6396  PopupMenu->Popup(MainScreen->Left + X, MainScreen->Top + Y + 43); // menu stops everything so reset timetable time when restarts,
6397  // new at v2.6.1, displays so that can't inadvertently click on a selection if click twice
6398  // 43 is the distance from the top of the screen to the top of TInterface
6399  TrainController->BaseTime = TDateTime::CurrentDateTime();
6401  Utilities->CallLogPop(40);
6402  return;
6403  }
6404  }
6405  }
6406  if(RouteMode == RouteContinuing) // clear a single element (clears whether use left or right mouse button) +allow in PreStart
6407  {
6408  TrainController->LogEvent("mbRight + RouteContinuing");
6410  Utilities->CallLogPop(41);
6411  return;
6412  }
6413 
6414  else if(RouteCancelFlag) // allow in PreStart
6415  {
6416  TrainController->LogEvent("mbRight + RouteCancelFlag");
6417  Screen->Cursor = TCursor(-11); // Hourglass;
6418  // stop clock as sometimes takes several seconds
6419  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
6421  if(AllRoutes->GetAllRoutesTruncateElement(0, HLoc, VLoc, ConsecSignalsRoute)) // updates LockedRouteClass
6422  {
6423  ClearandRebuildRailway(6); // to replot new shorter route
6424  }
6426  TrainController->BaseTime = TDateTime::CurrentDateTime();
6428  Screen->Cursor = TCursor(-2); // Arrow
6429  }
6430 
6431  else // gap flashing, don't allow to interfere with RouteCancelFlag
6432  {
6433  TrainController->LogEvent("mbRight, GapFlashingInOperOrPreStartMode");
6434  int Position;
6435  TTrackElement TrackElement;
6436  if(Track->FindNonPlatformMatch(4, HLoc, VLoc, Position, TrackElement))
6437  {
6438  ;
6439  }
6440  {
6441  if((TrackElement.TrackType == GapJump) && (TrackElement.Conn[0] > -1))
6442  {
6443  if((TrackElement.TrainIDOnElement == -1) && (Track->TrackElementAt(818, TrackElement.Conn[0]).TrainIDOnElement == -1))
6444  {
6445  // don't flash if train on either gap element
6446  Track->GapFlashGreenPosition = TrackElement.Conn[0];
6451  Track->GapFlashRedPosition = Position;
6456  Track->GapFlashFlag = true;
6457  }
6458  }
6459  }
6460  Utilities->CallLogPop(42);
6461  return; // covers above else & included here in case any more usermodes added later
6462  }
6463  }
6464  // deal with gap selection - if no other right button selection - apply for any mode (also included in OperMode above)
6465  TrainController->LogEvent("mbRight, GapFlashingNotOperOrPreStartMode");
6466  int Position;
6467  TTrackElement TrackElement;
6468  if(Track->FindNonPlatformMatch(18, HLoc, VLoc, Position, TrackElement))
6469  {
6470  ;
6471  }
6472  {
6473  if((TrackElement.TrackType == GapJump) && (TrackElement.Conn[0] > -1))
6474  {
6475  if((TrackElement.TrainIDOnElement == -1) && (Track->TrackElementAt(819, TrackElement.Conn[0]).TrainIDOnElement == -1))
6476  {
6477  // don't flash if train on either gap element
6478  Track->GapFlashGreenPosition = TrackElement.Conn[0];
6482  Track->GapFlashRedPosition = Position;
6486  Track->GapFlashFlag = true;
6487  }
6488  }
6489  }
6490  Utilities->CallLogPop(67);
6491  return; // covers above else & included here in case any more usermodes added later
6492  }
6493 
6494 // Left Mouse Button Functions
6495  if(RouteCancelFlag)
6496  {
6498  }
6499  mbLeftDown = true;
6500 
6501  if(Level2TrackMode == AddTrack)
6502  {
6503  TrainController->LogEvent("mbLeft + AddTrack");
6504  Screen->Cursor = TCursor(-11); // Hourglass;
6506  bool TrackLinkingRequiredFlag;
6507  int CurrentTag;
6508  TSpeedButton *TempSpeedButton = 0;
6509  if(CurrentSpeedButton)
6510  {
6511  CurrentTag = CurrentSpeedButton->Tag;
6512  TempSpeedButton = CurrentSpeedButton;
6513  }
6514  else
6515  {
6516  CurrentTag = 0;
6517  }
6518  bool InternalChecks = true;
6519  Track->PlotAndAddTrackElement(1, CurrentTag, 0, HLoc, VLoc, TrackLinkingRequiredFlag, InternalChecks);
6520  // above now has extra zero 'Aspect' parameter at v2.2.0 so can distinguish between adding track and pasting
6521  EditMenu->Enabled = true;
6522  if(Track->NamedLocationElementAt(1, HLoc, VLoc))
6523  {
6524  ClearandRebuildRailway(7); // so named location graphics plotted correctly
6525  }
6526  if(TrackLinkingRequiredFlag)
6527  {
6528  Track->SetTrackFinished(false);
6529  }
6530  SetTrackBuildImages(10);
6531  SetGapsButton->Enabled = false; // if conditions have changed need to reset buttons, best not calling SetLevel2TrackMode as that
6532  TrackOKButton->Enabled = false; // calls Clearand.. if gridflag set & takes a long time
6533  if(Track->GapsUnset(2))
6534  {
6535  SetGapsButton->Enabled = true;
6536  }
6537  // only enable if there are gaps still to be set (returns false for no track)
6538  else
6539  {
6540  if(!(Track->NoActiveTrack(1)) && !(Track->IsTrackFinished()))
6541  {
6542  TrackOKButton->Enabled = true;
6543  }
6544  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
6545  }
6546  if(!(Track->IsTrackFinished())) // can only set lengths for several elements together if TrackFinished
6547  {
6548  SetLengthsButton->Enabled = false;
6549  }
6550  if(TempSpeedButton) // restore button if was pressed
6551  {
6552  CurrentSpeedButton = TempSpeedButton;
6553  CurrentSpeedButton->Down = true;
6554  }
6555  Screen->Cursor = TCursor(-2); // Arrow
6556  Utilities->CallLogPop(44);
6557  return;
6558  }
6559 
6560  else if(Level2TrackMode == AddGraphic)
6561  {
6562  TrainController->LogEvent("mbLeft + AddGraphic");
6563 // ResetChangedFileDataAndCaption(, false); //moved to later after 2.7.0 in case can't find it
6564  TUserGraphicItem NewGI;
6565  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
6566  if(UGMIt != Track->UserGraphicMap.end()) // if it is the end then nothing was found
6567  {
6568  NewGI.UserGraphic = UGMIt->second;
6569  NewGI.Width = UGMIt->second->Width;
6570  NewGI.Height = UGMIt->second->Height;
6572  NewGI.HPos = X + (Display->DisplayOffsetH * 16);
6573  NewGI.VPos = Y + (Display->DisplayOffsetV * 16);
6574  Track->UserGraphicVector.push_back(NewGI);
6575  Display->PlotAndAddUserGraphic(1, NewGI);
6576  ResetChangedFileDataAndCaption(24, false); // moved to here after 2.7.0
6577  }
6578  else
6579  {
6580  ShowMessage("Unable to find graphic file " + SelectedGraphicFileName + ". Check it still exists.");
6581  Utilities->CallLogPop(2195);
6582  return;
6583  }
6584  MoveTextOrGraphicButton->Enabled = true;
6585  EditMenu->Enabled = true;
6586  Utilities->CallLogPop(2182);
6587  return;
6588  }
6589 
6590  else if(Level2TrackMode == AddLocationName)
6591  {
6592  TrainController->LogEvent("mbLeft + AddLocationName");
6593 // ResetChangedFileDataAndCaption(, true); moved after 2.7.0 to LocationNameKeyUp in case nothing changed
6594  bool FoundFlag;
6595  TTrackElement TrackElement;
6596  AnsiString NameString;
6597  TTrack::TIMPair InactivePair = Track->GetVectorPositionsFromInactiveTrackMap(1, HLoc, VLoc, FoundFlag);
6598  if(!FoundFlag)
6599  {
6600  Utilities->CallLogPop(45);
6601  return; // inactive element not found (has to be a platform or named non-station location, can't select any other element)
6602  }
6603  TTrackElement& InactiveTrackElement1 = Track->InactiveTrackElementAt(28, InactivePair.first);
6604  TTrackElement& InactiveTrackElement2 = Track->InactiveTrackElementAt(29, InactivePair.second); // may be same element if only 1
6605  TTrackElement& ValidElement = InactiveTrackElement1;
6606  unsigned int ValidPosition;
6607  if((InactiveTrackElement1.TrackType != Platform) && (InactiveTrackElement2.TrackType != Platform) &&
6608  (InactiveTrackElement1.TrackType != NamedNonStationLocation) && (InactiveTrackElement2.TrackType != NamedNonStationLocation) &&
6609  (InactiveTrackElement1.TrackType != Concourse) && (InactiveTrackElement2.TrackType != Concourse))
6610  {
6611  Utilities->CallLogPop(46);
6612  return; // element not valid
6613  }
6614  if((InactiveTrackElement1.TrackType == Platform) || (InactiveTrackElement1.TrackType == NamedNonStationLocation) ||
6615  (InactiveTrackElement1.TrackType == Concourse))
6616  {
6617  ValidElement = InactiveTrackElement1;
6618  ValidPosition = InactivePair.first;
6619  }
6620  else if((InactiveTrackElement2.TrackType == Platform) || (InactiveTrackElement2.TrackType == NamedNonStationLocation) ||
6621  (InactiveTrackElement2.TrackType == Concourse))
6622  {
6623  ValidElement = InactiveTrackElement2;
6624  ValidPosition = InactivePair.second;
6625  }
6626  // now have required element as ValidElement & position in InactiveTrackvector as ValidPosition
6627 
6628  // put a square box round element to show selection
6629  Display->Rectangle(0, HLoc * 16, VLoc * 16, clB0G0R5, 0, 2);
6630  LocationNameTextBox->Visible = true;
6631  LocationNameTextBox->SetFocus();
6632  NameString = Track->GetLocationName(ValidPosition);
6633  LocationNameTextBox->Text = NameString;
6634  InfoPanel->Visible = true;
6635  InfoPanel->Caption = "NAMING LOCATIONS: Enter name, 'Carriage Return' to accept, 'Escape' to quit";
6636 
6637  Track->LNPendingList.clear();
6638  Track->LNPendingList.insert(Track->LNPendingList.end(), ValidPosition);
6639  Level2TrackMode = NoTrackMode; // if leave as AddLocationName can select other squares before enter name
6640  Utilities->CallLogPop(47);
6641  return;
6642  }
6643 
6644  else if(Level2TrackMode == DistanceStart) // new for extended distances - similar to !PrefDirContinuing
6645  // prior to selecting start element
6646  {
6647  TrainController->LogEvent("mbLeft + DistanceStart");
6648 // ResetChangedFileDataAndCaption(, true); dropped after 2.7.0 in case only checking, moved to buttons in TracklengthPanel
6649  if(ConstructPrefDir->GetPrefDirStartElement(0, HLoc, VLoc))
6650  {
6653  SetLevel1Mode(65);
6655  SetLevel2TrackMode(30);
6656  }
6657  Utilities->CallLogPop(48);
6658  return;
6659  }
6660 
6661  else if(Level2TrackMode == DistanceContinuing) // new for extended distances - similar to PrefDirContinuing
6662  // prior to selecting finish element
6663  {
6664  TrainController->LogEvent("mbLeft + DistanceContinuing");
6665 // ResetChangedFileDataAndCaption(, true); dropped after 2.7.0 in case only checking, moved to buttons in TracklengthPanel
6666  bool FinishElement = false, LeadingPointsAtLastElement = false;
6667  Screen->Cursor = TCursor(-11); // Hourglass;
6668  if((ConstructPrefDir->PrefDirSize() != 1) || (ConstructPrefDir->GetFixedPrefDirElementAt(181, 0).HLoc != HLoc) ||
6669  (ConstructPrefDir->GetFixedPrefDirElementAt(182, 0).VLoc != VLoc))
6670  {
6671  // not same as start element
6672  if(ConstructPrefDir->GetNextPrefDirElement(0, HLoc, VLoc, FinishElement))
6673  {
6676  ConstructPrefDir->CalcDistanceAndSpeed(1, OverallDistance, OverallSpeedLimit, LeadingPointsAtLastElement);
6677  if(FinishElement)
6678  {
6679  TrackLengthPanel->Visible = true;
6680  TrackLengthPanel->SetFocus();
6681  InfoPanel->Visible = true;
6682  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Set values (overall length), or right click to cancel/truncate";
6683  RestoreAllDefaultLengthsButton->Enabled = true;
6684  ResetDefaultLengthButton->Enabled = true;
6685  LengthOKButton->Enabled = true;
6686  DistanceBox->Text = AnsiString(OverallDistance);
6687  if(OverallSpeedLimit > -1)
6688  {
6689  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
6690  }
6691  else
6692  {
6693  SpeedLimitBox->Text = "Mixed";
6694  }
6696  Screen->Cursor = TCursor(-2); // Arrow
6697  Utilities->CallLogPop(1527);
6698  return;
6699  }
6700  else
6701  {
6702  if(!LeadingPointsAtLastElement)
6703  {
6704  TrackLengthPanel->Visible = true;
6705  TrackLengthPanel->SetFocus();
6706  InfoPanel->Visible = true;
6707  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
6708  RestoreAllDefaultLengthsButton->Enabled = true;
6709  ResetDefaultLengthButton->Enabled = true;
6710  LengthOKButton->Enabled = true;
6711  DistanceBox->Text = AnsiString(OverallDistance);
6712  if(OverallSpeedLimit > -1)
6713  {
6714  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
6715  }
6716  else
6717  {
6718  SpeedLimitBox->Text = "Mixed";
6719  }
6720  // Level2TrackMode = DistanceContinuing;
6721  // SetLevel2TrackMode();
6722  }
6723  else
6724  {
6725  TrackLengthPanel->Visible = true;
6726  TrackLengthPanel->SetFocus();
6727  InfoPanel->Visible = true;
6728  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Can't end on leading points, need to continue or truncate";
6729  RestoreAllDefaultLengthsButton->Enabled = false;
6730  ResetDefaultLengthButton->Enabled = false;
6731  LengthOKButton->Enabled = false;
6732  // Level2TrackMode = DistanceContinuing;
6733  // SetLevel2TrackMode();
6734  }
6735  }
6736  }
6737  }
6738  else // same as start element
6739  {
6742  SetLevel2TrackMode(54);
6743  Screen->Cursor = TCursor(-2); // Arrow
6744  Utilities->CallLogPop(1713);
6745  return;
6746  }
6748  Screen->Cursor = TCursor(-2); // Arrow
6749  Utilities->CallLogPop(1490);
6750  return;
6751  }
6752 
6753  else if(Level2TrackMode == GapSetting)
6754  {
6755  TrainController->LogEvent("mbLeft + GapSetting");
6756 // ResetChangedFileDataAndCaption(, true); moved to later after 2.7.0 in case can't set it
6757  // HighLightOneGap already called once from SetLevel2TrackMode so have all gap element values set
6758  // & it is highlighted
6759  if(!(Track->FindSetAndDisplayMatchingGap(1, HLoc, VLoc)))
6760  {
6761  Utilities->CallLogPop(50);
6762  return; // true if finds one
6763  }
6764  ResetChangedFileDataAndCaption(11, true); // moved to here after 2.7.0 in case can't set it
6765  InfoPanel->Visible = true;
6766  InfoPanel->Caption = "CONNECTING GAPS: Connecting element selected";
6767  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
6768  Delay(0, 500); // 500 msec delay before next selection requested
6769 
6770  // ClearandRebuildRailway(8);//get rid of gap selections
6771  // need to call this later when new gap displayed, else old gap remains
6772 
6773  // now back to highlighting next gap
6774  // bool LocError = false;
6775  if(!(HighLightOneGap(1, HLoc, VLoc)))
6776  {
6777  // all gaps set
6778  ShowMessage("All gaps set");
6779  if(Level2TrackMode == AddTrack)
6780  {
6782  SetLevel1Mode(66);
6783  SetLevel2TrackMode(31);
6784  }
6785  else
6786  {
6788  SetLevel1Mode(37);
6789  }
6790  ClearandRebuildRailway(9); // get rid of last gap ellipse
6791  Utilities->CallLogPop(51);
6792  return;
6793  }
6794  // here if one gap highlighted so return to user to allow corresponding gap to be selected
6795  // by another call to MainScreenMouseDown
6796  }
6797 
6798  else if(Level2TrackMode == AddText)
6799  {
6800  TrainController->LogEvent("mbLeft + AddText");
6801 // ResetChangedFileDataAndCaption(, true); moved after 2.7.0 to TextBoxKeyPress in case nothing changed
6802  // X & Y are relative to Display output, but TextBox is placed relative to Form
6803  // if mouse position on first character of an existing piece of text reload it into the editor
6804 
6805  bool TextFoundFlag = false;
6806  int TrueX = 0, TrueY = 0;
6807  AnsiString ExistingText = "";
6809  TFont *ExistingTextFont = new TFont;
6810  int ExistingTextHPos = 0, ExistingTextVPos = 0;
6811  Track->GetTruePositionsFromScreenPos(1, TrueX, TrueY, X, Y);
6812  if(!TextHandler->TextVector.empty())
6813  {
6814  for(TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin(); TextPtr--)
6815  {
6816  if((TrueX >= TextPtr->HPos) && (TrueX < (TextPtr->HPos + abs(TextPtr->Font->Height))) && (TrueY >= TextPtr->VPos) && (TrueY <
6817  (TextPtr->VPos + abs(TextPtr->Font->Height))))
6818  {
6819  ExistingText = TextPtr->TextString;
6820  ExistingTextFont->Assign(TextPtr->Font);
6821  ExistingTextHPos = TextPtr->HPos;
6822  ExistingTextVPos = TextPtr->VPos;
6823  TextFoundFlag = true;
6824  TextHandler->TextErase(9, TrueX, TrueY, ExistingText);
6825  break;
6826  } // if ....
6827 
6828  } // for TextPtr...
6829  } // if !TextVector...
6830 
6831  if(TextFoundFlag)
6832  {
6833  TextBox->Left = ExistingTextHPos + Display->Left() - (Display->DisplayOffsetH * 16) - 3;
6834  TextBox->Top = ExistingTextVPos + Display->Top() - (Display->DisplayOffsetV * 16) - 3;
6835  TextBox->Font->Assign(ExistingTextFont);
6836  Display->SetFont(ExistingTextFont);
6837  Text_X = ExistingTextHPos;
6838  Text_Y = ExistingTextVPos;
6839  }
6840  else
6841  {
6842  TextBox->Left = (TextOrUserGraphicGridVal * div((Display->Left() + X), TextOrUserGraphicGridVal).quot) - 3;
6843  TextBox->Top = (TextOrUserGraphicGridVal * div((Display->Top() + Y), TextOrUserGraphicGridVal).quot) - 3;
6844  TextBox->Font->Assign(Display->GetFont());
6845  Text_X = TextOrUserGraphicGridVal * div(NoOffsetX, TextOrUserGraphicGridVal).quot;
6846  Text_Y = TextOrUserGraphicGridVal * div(NoOffsetY, TextOrUserGraphicGridVal).quot;
6847  }
6848  TextBox->Visible = true;
6849  TextBox->SetFocus();
6850  if(TextFoundFlag)
6851  {
6852  TextBox->Text = ExistingText;
6853  }
6854  else
6855  {
6856  TextBox->Text = "New Text: CR=end, ESC=quit";
6857  }
6858  TextBox->Width = (abs(TextBox->Font->Height) * TextBox->Text.Length() * 0.7);
6859  TextBox->SelectAll();
6860  delete ExistingTextFont;
6861  ClearandRebuildRailway(29); // to remove old text if replaced
6863  Utilities->CallLogPop(1775);
6864  return; // If text input go no further
6865  }
6866 
6868  {
6869  TrainController->LogEvent("mbLeft + MoveTextOrGraphic");
6870 // ResetChangedFileDataAndCaption(, true); moved after 2.7.0 to later in case nothing found
6871  // int HPosInput;// = X + (Display->DisplayOffsetH * 16);
6872  // int VPosInput;// = Y + (Display->DisplayOffsetV * 16);
6873  // Track->GetTruePositionsFromScreenPos(HPosInput, VPosInput, X, Y);
6874  // StartX = X + (Display->DisplayOffsetH * 16);
6875  // StartY = Y + (Display->DisplayOffsetV * 16);
6878  if(!TextFoundFlag) // give precedence to text
6879  {
6882  {
6883  ResetChangedFileDataAndCaption(13, true); // moved here after 2.7.0 to save only if something found
6884  }
6885  }
6886  else
6887  {
6888  ResetChangedFileDataAndCaption(27, true); // and here
6889  }
6890  Utilities->CallLogPop(53);
6891  return; // if text move selected don't permit anything else
6892  }
6893 
6894  else if(Level2TrackMode == TrackSelecting)
6895  /* When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
6896  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
6897  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
6898  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
6899  selected rectangle.
6900  */
6901  {
6902  TrainController->LogEvent("mbLeft + TrackSelecting");
6903  ClearandRebuildRailway(10); // to get rid of earlier rectangles
6904  SelectStartPair.first = HLoc;
6905  SelectStartPair.second = VLoc;
6906  }
6907 
6908  else if((Level2TrackMode == CopyMoving) || (Level2TrackMode == CutMoving))
6909  /* The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
6910  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
6911  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
6912  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
6913  */
6914  {
6915  TrainController->LogEvent("mbLeft + CopyMoving or CutMoving");
6916 // ResetChangedFileDataAndCaption(, true); moved after 2.7.0 to later in case don't proceed
6917  if((X < ((SelectBitmapHLoc - Display->DisplayOffsetH) * 16) + 4) ||
6918  (X > ((SelectBitmapHLoc + (SelectBitmap->Width / 16) - Display->DisplayOffsetH) * 16) - 4))
6919  {
6920  SelectPickedUp = false;
6921  Utilities->CallLogPop(54);
6922  return; // within 4 pixels of outside of horizontal area (4 pixels are so can't push selection off edge of screen)
6923  }
6924  if((Y < ((SelectBitmapVLoc - Display->DisplayOffsetV) * 16) + 4) ||
6925  (Y > ((SelectBitmapVLoc + (SelectBitmap->Height / 16) - Display->DisplayOffsetV) * 16) - 4))
6926  {
6927  SelectPickedUp = false;
6928  Utilities->CallLogPop(55);
6929  return; // within 4 pixels of outside of vertical area (4 pixels are so can't push selection off edge of screen)
6930  }
6931  else
6932  {
6933  SelectPickedUp = true;
6934  }
6935  ResetChangedFileDataAndCaption(14, true); // moved here after 2.7.0 in case don't proceed
6938  }
6939 
6941  {
6942  TrainController->LogEvent("mbLeft + != PrefDirContinuing");
6943 // ResetChangedFileDataAndCaption(, false); //moved after 2.7.0 to later in case don't click on element
6944 // RlyFile = false; - don't alter this just for PrefDir changes
6945  if(ConstructPrefDir->GetPrefDirStartElement(1, HLoc, VLoc))
6946  {
6947  ResetChangedFileDataAndCaption(15, false); // moved after 2.7.0 to here
6951  }
6952  Utilities->CallLogPop(56);
6953  return;
6954  }
6955 
6957  {
6958  TrainController->LogEvent("mbLeft + PrefDirContinuing");
6959 // ResetChangedFileDataAndCaption(, false); //moved after 2.7.0 to later in case don't click on element
6960 // RlyFile = false; - don't alter this just for PrefDir changes
6961  bool FinishElement;
6962  Screen->Cursor = TCursor(-11); // Hourglass;
6963  if((ConstructPrefDir->PrefDirSize() != 1) || (ConstructPrefDir->GetFixedPrefDirElementAt(183, 0).HLoc != HLoc) ||
6964  (ConstructPrefDir->GetFixedPrefDirElementAt(184, 0).VLoc != VLoc))
6965  {
6966  // not same as start element
6967  if(ConstructPrefDir->GetNextPrefDirElement(1, HLoc, VLoc, FinishElement))
6968  {
6970  ResetChangedFileDataAndCaption(16, false); // moved after 2.7.0 to here
6971  if(FinishElement)
6972  {
6973  ShowMessage("Preferred direction added");
6976  SetLevel1Mode(16);
6977  Screen->Cursor = TCursor(-2); // Arrow
6978  Utilities->CallLogPop(57);
6979  return;
6980  }
6981  else
6982  {
6985  }
6986  // set again since 1st time
6987  // PrefDir vector only had start element & Truncate wasn't enabled, also need
6988  // to do the checks for Loop & End for each element as it is added
6989  }
6990  }
6991  else // same as start element
6992  {
6995  SetLevel1Mode(121);
6996  Screen->Cursor = TCursor(-2); // Arrow
6997  Utilities->CallLogPop(1714);
6998  return;
6999  }
7000  Screen->Cursor = TCursor(-2); // Arrow
7001  Utilities->CallLogPop(58);
7002  return;
7003  }
7004 
7006  {
7007  TrainController->LogEvent("mbLeft + PrefDirSelecting");
7008  ClearandRebuildRailway(56); // to get rid of earlier rectangles
7009  SelectStartPair.first = HLoc;
7010  SelectStartPair.second = VLoc;
7011  }
7012 
7013  else if(Level1Mode == OperMode)
7014  {
7015  if((Level2OperMode == Operating) && CallingOnButton->Down && CallingOnButton->Enabled)
7016  {
7017  TrainController->LogEvent("mbLeft + Operating & CallingOnButton->Down");
7018  int Position;
7019  TTrackElement TrackElement;
7020  if(Track->FindNonPlatformMatch(2, HLoc, VLoc, Position, TrackElement))
7021  {
7022  if(TrackElement.TrackType != SignalPost)
7023  {
7024  CallingOnButton->Down = false;
7025 // InfoPanel->Visible = false; //dropped at v1.3.0, not sure what purpose intended to serve but don't want to lose the info panel as did with this here also added line below to reset
7027  Utilities->CallLogPop(59);
7028  return;
7029  }
7030  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
7031  {
7033  {
7035  x).LeadExitPos] == Position) && (TrackElement.Config[Track->TrackElementAt(429, TrainController->TrainVectorAt(28,
7037  {
7038  // found it!
7039 /*
7040  if(TrackElement.SpeedTag == 68)
7041  {
7042  Display->PlotOutput(0, (HLoc * 16), (VLoc * 16), RailGraphics->bm68CallingOn);
7043  }
7044  if(TrackElement.SpeedTag == 69)
7045  {
7046  Display->PlotOutput(1, (HLoc * 16), (VLoc * 16), RailGraphics->bm69CallingOn);
7047  }
7048  if(TrackElement.SpeedTag == 70)
7049  {
7050  Display->PlotOutput(2, (HLoc * 16), (VLoc * 16), RailGraphics->bm70CallingOn);
7051  }
7052  if(TrackElement.SpeedTag == 71)
7053  {
7054  Display->PlotOutput(3, (HLoc * 16), (VLoc * 16), RailGraphics->bm71CallingOn);
7055  }
7056  if(TrackElement.SpeedTag == 72)
7057  {
7058  Display->PlotOutput(4, (HLoc * 16), (VLoc * 16), RailGraphics->bm72CallingOn);
7059  }
7060  if(TrackElement.SpeedTag == 73)
7061  {
7062  Display->PlotOutput(5, (HLoc * 16), (VLoc * 16), RailGraphics->bm73CallingOn);
7063  }
7064  if(TrackElement.SpeedTag == 74)
7065  {
7066  Display->PlotOutput(6, (HLoc * 16), (VLoc * 16), RailGraphics->bm74CallingOn);
7067  }
7068  if(TrackElement.SpeedTag == 75)
7069  {
7070  Display->PlotOutput(7, (HLoc * 16), (VLoc * 16), RailGraphics->bm75CallingOn);
7071  }
7072 */
7073  Track->TrackElementAt(430, Position).CallingOnSet = true;
7074  Track->PlotSignal(13, Track->TrackElementAt(893, Position), Display);
7075 // added at v 1.3.0 in place of the above to ensure ground signals (as well as others) plot correctly for proceed
7076  // have to call after CallingOnSet becomes true & can't use TrackElement as that still has CallingOnSet false
7077  ClearandRebuildRailway(69); // added at v1.3.0 to replot route on element after PlotSignal above
7080  CallingOnButton->Down = false;
7082 
7083 // set an unrestricted route into the station (just to the first platform) from the stop signal (note that it may be last in an autosigs
7084 // route) but remove any single route elements first (can't reach here if constructing a route), else may try to extend a route that
7085 // has been removed (only a precaution, shouldn't cause any probs whether single route set or not)
7086  for(unsigned int x = 0; x < AllRoutes->AllRoutesSize(); x++)
7087  {
7088  if(AllRoutes->GetFixedRouteAt(192, x).PrefDirSize() == 1)
7089  {
7090  // only allow route element to be removed if not selected for a route start otherwise
7091  // StartSelectionRouteID will be set & will fail at convert
7093  {
7095  AllRoutes->RemoveRouteElement(21, PDE.HLoc, PDE.VLoc, PDE.GetELink());
7096  TrainController->LogEvent("SingleRouteElementRemovedDuringCallon, H = " + AnsiString(PDE.HLoc) + ", V = " +
7097  AnsiString(PDE.VLoc));
7098  }
7099  }
7100  }
7101 
7102 // find the correct entry in CallonVector - i.e. where Position == RouteStartEntry
7103  for(unsigned int x = 0; x < AllRoutes->CallonVector.size(); x++)
7104  {
7105  if(AllRoutes->CallonVector.at(x).RouteStartPosition == Position)
7106  {
7107  // found it
7108  if(!(AllRoutes->CallonVector.at(x).RouteOrPartRouteSet))
7109  // if RouteOrPartRouteSet false then set an unrestricted route into platform
7110  {
7111  bool PointsChanged = false;
7112  IDInt ReqPosRouteID(-1);
7113  TOneRoute *NewRoute = new TOneRoute;
7114  bool CallonTrue = true;
7115  if(NewRoute->GetNonPreferredRouteStartElement(1,
7116  Track->TrackElementAt(841, AllRoutes->CallonVector.at(x).RouteStartPosition).HLoc,
7117  Track->TrackElementAt(842, AllRoutes->CallonVector.at(x).RouteStartPosition).VLoc, CallonTrue))
7118  {
7119  if(NewRoute->GetNextNonPreferredRouteElement(1,
7120  Track->TrackElementAt(843, AllRoutes->CallonVector.at(x).PlatformPosition).HLoc,
7121  Track->TrackElementAt(844, AllRoutes->CallonVector.at(x).PlatformPosition).VLoc, CallonTrue,
7122  ReqPosRouteID, PointsChanged))
7123  {
7124  if(!PointsChanged) // shouldn't be changed, something wrong if true so don't plot route
7125  {
7126  NewRoute->ConvertAndAddNonPreferredRouteSearchVector(3, ReqPosRouteID);
7127  ClearandRebuildRailway(67); // to plot the route (only finds one so won't call repeatedly)
7128  }
7129  }
7130  }
7131  delete NewRoute;
7132  }
7133  }
7134  }
7135 // InfoPanel->Visible = false;
7136  Utilities->CallLogPop(60);
7137  return;
7138  }
7139  }
7140  }
7141  }
7142  CallingOnButton->Down = false;
7144  Utilities->CallLogPop(61);
7145  return;
7146  }
7147 /* get 1st element, first check if selected points, not in existing route, & in RouteNotStarted mode
7148  if so, set all the flash values, Track->PointFlashFlag & start time, then exit for flasher to take over.
7149  If any of above conditions not met then treat as route selection, setting route flasher if
7150  route continuing.
7151 */
7152 
7153  if((Level2OperMode == Operating) || (Level2OperMode == PreStart)) // not 'else if' as both may apply
7154  // disallow route setting if paused
7155  {
7156  if(Level2OperMode == PreStart)
7157  {
7158  PointsFlashDuration = 0.0;
7161  }
7162  else
7163  {
7164  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
7165  if(TTClockSpeed < 1)
7166  {
7167  TempSpeedVal = TTClockSpeed;
7168  }
7169  PointsFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
7172  }
7173  if(RouteMode == RouteNotStarted)
7174  {
7175  TrainController->LogEvent("mbLeft + RouteNotStarted");
7176  int Position;
7177  TTrackElement TrackElement;
7178  if(Track->FindNonPlatformMatch(3, HLoc, VLoc, Position, TrackElement))
7179  {
7180  if((TrackElement.TrackType == Points) && !(AllRoutes->TrackIsInARoute(1, Position, 0))
7182  // Flash selected points & changeover if appropriate
7183  // need !Track->PointFlashFlag to prevent another point being selected while another is flashing, & !Track->RouteFlashFlag
7184  // to ensure user only does one thing at a time
7185  {
7186  if(TrackElement.TrainIDOnElement > -1)
7187  {
7188  TrainController->StopTTClockMessage(1, "Can't change points under a train!");
7189  Utilities->CallLogPop(62);
7190  return;
7191  }
7192  PointFlash->SetScreenHVSource(1, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
7193 
7194 /*
7195  This used to try to allow any linked trailing edges to cause both points to change, but no good if
7196  there are two adjacent crossovers, where both trailing edges are linked to two different points.
7197  The wrong link might be chosen. Also doubtful if applying a strict order of checks would work, since
7198  may be obscure configurations that would be wrong. This function bypasses the MatchingPoint check, which
7199  ensures that there are no obscure links. Hence better to stick with original.
7200 
7201  //check if trailing edge linked to another point trailing edge
7202  int DivergingPosition = TrackElement.Conn[1];
7203  TTrackElement DivergingElement = Track->TrackElementAt(431, TrackElement.Conn[1]);
7204  DivergingPointVectorPosition = -1;
7205  if((DivergingElement.TrackType == Points) &&
7206  ((DivergingElement.Conn[1] == Position) || (DivergingElement.Conn[3] == Position)))
7207  {
7208  if(AllRoutes->TrackIsInARoute(, DivergingPosition))
7209  {
7210  ShowMessage("Linked points Locked");
7211  }
7212  else DivergingPointVectorPosition = DivergingPosition;
7213  }
7214  else
7215  {
7216  DivergingPosition = TrackElement.Conn[3];
7217  DivergingElement = Track->TrackElementAt(432, TrackElement.Conn[3]);
7218  if((DivergingElement.TrackType == Points) &&
7219  ((DivergingElement.Conn[1] == Position) || (DivergingElement.Conn[3] == Position)))
7220  {
7221  if(AllRoutes->TrackIsInARoute(, DivergingPosition))
7222  {
7223  ShowMessage("Linked points locked");
7224  }
7225  else DivergingPointVectorPosition = DivergingPosition;
7226  }
7227  }
7228  Track->PointFlashFlag = true;
7229  PointFlashVectorPosition = Position;
7230  PointFlashStartTime = TrainController->TTClockTime;
7231  [close curly bracket - if include it matches earlier non-commented one!]
7232 */
7233  TTrackElement DivergingElement = Track->TrackElementAt(433, TrackElement.Conn[3]);
7234  int DivergingPosition = TrackElement.Conn[3];
7235  if((DivergingElement.TrackType == Points) && (DivergingElement.Conn[3] == Position) && (Track->MatchingPoint(1, Position,
7236  DivergingPosition))) // full match inc same attributes
7237  {
7238  if(AllRoutes->TrackIsInARoute(4, DivergingPosition, 0))
7239  {
7240  TrainController->StopTTClockMessage(2, "Linked points locked");
7241  }
7242  else
7243  {
7244  Track->PointFlashFlag = true;
7245  PointFlashVectorPosition = Position;
7246  DivergingPointVectorPosition = DivergingPosition;
7248  }
7249  }
7250  else // no matching point, just change this point
7251  {
7252  Track->PointFlashFlag = true;
7253  PointFlashVectorPosition = Position;
7256  }
7257  }
7258 
7259  else if(Track->IsLCAtHV(59, HLoc, VLoc) && !Track->PointFlashFlag && !Track->RouteFlashFlag)
7260  // level crossing added at v2.6.0 to allow manual LC changing
7261  {
7262  if(Track->GetInactiveTrackElementFromTrackMap(5, HLoc, VLoc).Attribute != 2) // 2 = LC changing state, can't click if changing
7263  {
7264  Track->LCChangeFlag = true;
7265  bool TrainPresent = false;
7266  if(Track->IsLCBarrierDownAtHV(4, HLoc, VLoc)) // if true then may be able to raise barriers
7267  {
7268  // first need to identify the LC in the BarriersDownVector
7269  int BDVectorPos = -1;
7270  if(Track->AnyLinkedBarrierDownVectorManual(1, HLoc, VLoc, BDVectorPos)) // looking for same position & manually closed
7271  {
7272  // this largely copied from ClockTimer2
7274  Track->BarriersDownVector.at(BDVectorPos).VLoc, ConstructRoute->SearchVector, TrainPresent))
7275  // returns true for route set or being set or train, and TrainPresent true if train on LC
7276  {
7277  TTrack::TActiveLevelCrossing CLC = Track->BarriersDownVector.at(BDVectorPos);
7278  // check if have exceeded the allowance (3 minutes for a train having passed or 0 for not) and add it to the overall excess time
7279  TDateTime TempExcessLCDownTime;
7280  if(Track->BarriersDownVector.at(BDVectorPos).ReducedTimePenalty)
7281  // this set in ClockTimer2, relies on train being on LC for >= 1 second
7282  {
7283  // get the 3 mins allowance - hard to imagine will pass in less than a second!
7284  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime - TDateTime(180.0 / 86400);
7285  }
7286  else
7287  {
7288  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime;
7289  }
7290  if(TempExcessLCDownTime > TDateTime(0))
7291  {
7292  TrainController->ExcessLCDownMins += (double(TempExcessLCDownTime) * 1440);
7293  }
7294  CLC.StartTime = TrainController->TTClockTime; // reset these 3 members
7297  Track->SetLinkedLevelCrossingBarrierAttributes(7, CLC.HLoc, CLC.VLoc, 2); // set attr to 2 for changing state
7298  Track->ChangingLCVector.push_back(CLC);
7299  Track->BarriersDownVector.erase(Track->BarriersDownVector.begin() + BDVectorPos);
7300  }
7301  }
7302  }
7303  else // lowering
7304  {
7305  // this largely copied from SetLCChangeValues
7306  TTrack::TActiveLevelCrossing ALC; // constructor sets ReducedTimePenalty to false
7307  ALC.HLoc = HLoc;
7308  ALC.VLoc = VLoc;
7310  ALC.BaseElementSpeedTag = TrackElement.SpeedTag;
7313  ALC.TypeOfRoute = 2;
7314  Track->SetLinkedManualLCs(0, HLoc, VLoc);
7315 // this sets all linked LC ConsecSignals values to 2 for manually lowered - differs from SetLCChangeValues which uses the route type
7316  Track->SetLinkedLevelCrossingBarrierAttributes(6, HLoc, VLoc, 2); // set attr to 2 for changing state
7317  Track->ChangingLCVector.push_back(ALC);
7319  {
7320  AnsiString Message =
7321  AnsiString("This will open the level crossing manually (it will show in green).\n\nA manually opened"
7322  " level crossing must be manually closed, and as soon as possible to avoid time penalties.\n\n" "This message will not be shown again."
7323  );
7324  TrainController->StopTTClockMessage(93, Message);
7326  }
7327  }
7328  }
7329  }
7330  else // route start
7331  {
7332  if(AutoSigsFlag)
7333  {
7334  AutoRouteStartMarker->SetScreenHVSource(2, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
7336  }
7337  else if(PreferredRoute) // added at v2.7.0, was ConsecSignalsRoute
7338  {
7339  SigRouteStartMarker->SetScreenHVSource(3, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
7341  }
7342  else
7343  {
7344  NonSigRouteStartMarker->SetScreenHVSource(4, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
7346  }
7347  if(PreferredRoute)
7348  {
7349  if(!Track->PointFlashFlag && !Track->RouteFlashFlag) // don't allow a route to start if a point changing or
7350  // another route building
7351  {
7352  ConstructRoute->ClearRoute(); // in case not empty though should be
7354  {
7355  if(AutoSigsFlag)
7356  {
7358  }
7359  else
7360  {
7362  }
7364  InfoPanel->Visible = true;
7365  if(Level2OperMode == PreStart)
7366  {
7367  InfoPanel->Caption = "PRE-START: Select next route location";
7368  }
7369  else
7370  {
7371  InfoPanel->Caption = "OPERATING: Select next route location";
7372  }
7373  }
7374  }
7375  Utilities->CallLogPop(63);
7376  return;
7377  }
7378  else // nonpreferred route
7379  {
7380  if(!Track->PointFlashFlag && !Track->RouteFlashFlag) // don't allow a route to start if a point changing or
7381  // another route building
7382  {
7383  ConstructRoute->ClearRoute(); // in case not empty though should be
7384  bool CallonFalse = false;
7385  if(ConstructRoute->GetNonPreferredRouteStartElement(0, HLoc, VLoc, CallonFalse))
7386  {
7389  InfoPanel->Visible = true;
7390  if(Level2OperMode == PreStart)
7391  {
7392  InfoPanel->Caption = "PRE-START: Select next route location";
7393  }
7394  else
7395  {
7396  InfoPanel->Caption = "OPERATING: Select next route location";
7397  }
7398  }
7399  }
7400  Utilities->CallLogPop(64);
7401  return;
7402  } // NonPreferred route
7403 
7404  } // TrackType != Points
7405 
7406  } // if(Track->FindNonPlatformMatch(HLoc, VLoc, Position, TrackElement))
7407 
7408  } // if(RouteMode == RouteNotStarted)
7409  else // RouteContinuing
7410  {
7411  TrainController->LogEvent("mbLeft + RouteContinuing");
7412  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
7415  AutoRouteStartMarker->PlotOriginal(14, Display); // if overlay not plotted will ignore
7416  SigRouteStartMarker->PlotOriginal(15, Display); // if overlay not plotted will ignore
7417  NonSigRouteStartMarker->PlotOriginal(16, Display); // if overlay not plotted will ignore
7418  Screen->Cursor = TCursor(-11); // Hourglass - also set to an hourglass when flashing, after found required
7419  // element, but this sets it to an hourglass while searching
7420  bool PointsChanged = false;
7421  if(PreferredRoute)
7422  {
7423  // route added to AllRoutes in GetNextRouteElement if valid
7424  // int ReqPosRouteNumber;
7426  ConstructRoute->ReqPosRouteID, PointsChanged))
7427  {
7428  Track->RouteFlashFlag = true;
7429  PreferredRouteFlag = true;
7430  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
7431  if(TTClockSpeed < 1)
7432  {
7433  TempSpeedVal = TTClockSpeed;
7434  }
7435  if(Level2OperMode == PreStart)
7436  {
7437  RouteFlashDuration = 0.0;
7438  }
7439  else if(PointsChanged)
7440  {
7441  RouteFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
7442  }
7443  else
7444  {
7445  RouteFlashDuration = AllRoutes->SignalsDelay * TempSpeedVal;
7446  }
7447  ConstructRoute->SetRouteFlashValues(1, AutoSigsFlag, true); // true for PrefDirRoute
7449  }
7450  else
7451  {
7453  }
7454  Screen->Cursor = TCursor(-2); // Arrow
7455  TrainController->BaseTime = TDateTime::CurrentDateTime();
7457  Utilities->CallLogPop(65);
7458  return;
7459  }
7460  else
7461  {
7462  bool CallonFalse = false;
7463  if(ConstructRoute->GetNextNonPreferredRouteElement(0, HLoc, VLoc, CallonFalse, ConstructRoute->ReqPosRouteID, PointsChanged))
7464  {
7465  Track->RouteFlashFlag = true;
7466  PreferredRouteFlag = false;
7467  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
7468  if(TTClockSpeed < 1)
7469  {
7470  TempSpeedVal = TTClockSpeed;
7471  }
7472  if(Level2OperMode == PreStart)
7473  {
7474  RouteFlashDuration = 0.0;
7475  }
7476  else if(PointsChanged)
7477  {
7478  RouteFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
7479  }
7480  else
7481  {
7482  RouteFlashDuration = AllRoutes->SignalsDelay * TempSpeedVal;
7483  }
7484  ConstructRoute->SetRouteFlashValues(2, false, false);
7486  }
7487  else
7488  {
7490  }
7491  }
7492  TrainController->BaseTime = TDateTime::CurrentDateTime();
7494  Screen->Cursor = TCursor(-2); // Arrow
7495  }
7496  Utilities->CallLogPop(66);
7497  return;
7498  }
7499  }
7500  Utilities->CallLogPop(68);
7501  }
7502  catch(const Exception &e)
7503  {
7504  ErrorLog(20, e.Message);
7505  }
7506 }
7507 
7508 // ---------------------------------------------------------------------------
7509 
7510 void TInterface::MainScreenMouseDown3(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
7511 // ZoomOut mode
7512 {
7513 // NB: DisplayZoomOutOffsetH & V take account of the Min & Max H & V values so don't need these again
7514  try
7515  {
7516  TrainController->LogEvent("MainScreenMouseDown3," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7517  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MainScreenMouseDown3," + AnsiString(Button) + "," + AnsiString(X) +
7518  "," + AnsiString(Y));
7519  if(Button != mbLeft)
7520  {
7521  // this routine new at v2.1.0. Allows railway moving for zoom-out mode
7524  WholeRailwayMoving = true;
7525  Screen->Cursor = TCursor(-22); // Four arrows;
7526  }
7527  else
7528  {
7529  InfoPanel->Visible = false; // reset infopanel in case not set later
7530  InfoPanel->Caption = "";
7531  int HRounding, VRounding;
7532  int TruePosH = (X / 4) + Display->DisplayZoomOutOffsetH;
7533  int TruePosV = (Y / 4) + Display->DisplayZoomOutOffsetV;
7534  // find nearest screen centre - from 30 to 210 horiz & from 18 to 126 vert
7535  if(TruePosH < 0)
7536  {
7537  HRounding = -(Utilities->ScreenElementWidth / 4);
7538  }
7539  else
7540  {
7541  HRounding = (Utilities->ScreenElementWidth / 4);
7542  }
7543  int CentreH = (((TruePosH + HRounding) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2));
7544  while((CentreH - Track->GetHLocMax()) >= (Utilities->ScreenElementWidth / 2))
7545  {
7546  CentreH -= (Utilities->ScreenElementWidth / 2);
7547  }
7548  while((Track->GetHLocMin() - CentreH) >= (Utilities->ScreenElementWidth / 2))
7549  {
7550  CentreH += (Utilities->ScreenElementWidth / 2);
7551  }
7552  if(TruePosV < 0)
7553  {
7554  VRounding = -(Utilities->ScreenElementHeight / 4);
7555  }
7556  else
7557  {
7558  VRounding = (Utilities->ScreenElementHeight / 4);
7559  }
7560  int CentreV = (((TruePosV + VRounding) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2));
7561  while((CentreV - Track->GetVLocMax()) >= (Utilities->ScreenElementHeight / 2))
7562  {
7563  CentreV -= (Utilities->ScreenElementHeight / 2);
7564  }
7565  while((Track->GetVLocMin() - CentreV) >= (Utilities->ScreenElementHeight / 2))
7566  {
7567  CentreV += (Utilities->ScreenElementHeight / 2);
7568  }
7569  Display->DisplayOffsetH = CentreH - (Utilities->ScreenElementWidth / 2);
7571 
7572  TLevel2OperMode TempLevel2OperMode = Level2OperMode;
7573  if(Level1Mode == BaseMode)
7574  {
7575  SetLevel1Mode(17);
7576  }
7577  else if(Level1Mode == TrackMode)
7578  {
7579  // set edit menu items
7581  PreventGapOffsetResetting = true; // when return from zoom by clicking screen don't force a return to the
7582  // displayed gap, user wants to display the clicked area
7583  SetLevel2TrackMode(32); // revert to earlier track mode from zoom
7584  PreventGapOffsetResetting = false;
7585  }
7586  else if(Level1Mode == PrefDirMode)
7587  {
7589  {
7590  SetLevel2PrefDirMode(3); // revert to earlier PrefDir mode from zoom
7591  }
7592  else
7593  {
7594  SetLevel1Mode(33); // if PrefDirSelecting revert to normap PrefDirMode
7595  }
7596  }
7597  // else if(Level1Mode == TrackMode) SetLevel1Mode();//just revert to basic track mode from zoom
7598  // else if(Level1Mode == PrefDirMode) SetLevel1Mode();//just revert to basic PrefDir mode from zoom
7599  else if(Level1Mode == TimetableMode)
7600  {
7601  InfoPanel->Visible = false;
7602  }
7603  // Not OperMode or RestartSessionOperMode as that resets the performance file
7604  else if(TempLevel2OperMode == Operating) // similar to SetLevel2OperMode but without resetting BaseTime
7605  {
7606  OperateButton->Enabled = true;
7607  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
7608  ExitOperationButton->Enabled = true;
7610  }
7611  else if(TempLevel2OperMode == Paused) // similar to SetLevel2OperMode but without resetting RestartTime
7612  {
7613  OperateButton->Enabled = true;
7614  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
7615  ExitOperationButton->Enabled = true;
7616  TTClockAdjButton->Enabled = true;
7619  }
7620  else if(TempLevel2OperMode == PreStart)
7621  {
7622  OperateButton->Enabled = true;
7623  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
7624  ExitOperationButton->Enabled = true;
7625  TTClockAdjButton->Enabled = true;
7627  }
7628  Display->ZoomOutFlag = false; // reset this after level modes called so gap flash stays set if set to begin with
7631  }
7632  Utilities->CallLogPop(69);
7633  }
7634  catch(const Exception &e)
7635  {
7636  ErrorLog(21, e.Message);
7637  }
7638 }
7639 
7640 // ---------------------------------------------------------------------------
7641 
7642 void __fastcall TInterface::MainScreenMouseMove(TObject *Sender, TShiftState Shift, int X, int Y)
7643 {
7644  try
7645  {
7646  // TrainController->LogEvent("MainScreenMouseMove," + AnsiString(X) + "," + AnsiString(Y)); //dropped at v0.6, too many events
7647  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseMove," + AnsiString(X) + "," + AnsiString(Y));
7648 
7649  if(!mbLeftDown && WholeRailwayMoving) // new at v2.1.0
7650  {
7651  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
7653  if(X < 0)
7654  {
7655  X = 0; // ensure pointer stays within display area
7656  }
7657  if(X > (MainScreen->Width - 1))
7658  {
7659  X = MainScreen->Width - 1;
7660  }
7661  if(Y < 0)
7662  {
7663  Y = 0;
7664  }
7665  if(Y > (MainScreen->Height - 1))
7666  {
7667  Y = MainScreen->Height - 1;
7668  }
7669  if(!Display->ZoomOutFlag)
7670  {
7671  int StartOffsetX = (X - StartWholeRailwayMoveHPos) % 16;
7672  int StartOffsetY = (Y - StartWholeRailwayMoveVPos) % 16;
7673  if((abs(X - StartWholeRailwayMoveHPos) >= 16) || (abs(Y - StartWholeRailwayMoveVPos) >= 16))
7674  {
7675  int NewH = X - StartWholeRailwayMoveHPos;
7676  int NewV = Y - StartWholeRailwayMoveVPos;
7677  Display->DisplayOffsetH -= NewH / 16;
7678  Display->DisplayOffsetV -= NewV / 16;
7679  StartWholeRailwayMoveHPos = X - StartOffsetX;
7680  StartWholeRailwayMoveVPos = Y - StartOffsetY;
7683  {
7685  }
7686  }
7687  }
7688 
7689  else
7690  {
7691  int StartZOffsetX = (X - StartWholeRailwayMoveHPos) % 4;
7692  int StartZOffsetY = (Y - StartWholeRailwayMoveVPos) % 4;
7693  if((abs(X - StartWholeRailwayMoveHPos) >= 4) || (abs(Y - StartWholeRailwayMoveVPos) >= 4))
7694  {
7695  int NewH = X - StartWholeRailwayMoveHPos;
7696  int NewV = Y - StartWholeRailwayMoveVPos;
7697  Display->DisplayZoomOutOffsetH -= NewH / 4;
7698  Display->DisplayZoomOutOffsetV -= NewV / 4;
7699  StartWholeRailwayMoveHPos = X - StartZOffsetX;
7700  StartWholeRailwayMoveVPos = Y - StartZOffsetY;
7701  Display->ClearDisplay(10);
7703  }
7704  }
7705  TrainController->BaseTime = TDateTime::CurrentDateTime();
7707  }
7708 
7709  else if(mbLeftDown)
7710  {
7712  /* [Repeated from MouseDown] - When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
7713  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
7714  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
7715  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
7716  selected rectangle.
7717  [New] At this point the select starting position has been defined in SelectStartPair, and the current mouse position is defined (wrt whole
7718  railway) in HLoc & VLoc from the screen positions X & Y by GetTrackLocsFromScreenPos. Both are incremented so that the rectangle
7719  includes the current point (if no mouse movement at all occurs then a 1 x 1 rectangle is displayed). Limits are set to prevent the
7720  displayed rectangle extending off screen. Edges are set at 60 & 36 rather than 59 & 35 because the defined rectangle excludes the
7721  rightmost and bottom HLoc & VLoc values, if 59 & 35 were used the right & bottom screen edges wouldn't be reached. A TRect is then
7722  defined from SelectStartPair and the HLoc/VLoc values, Clearand... called to clear earlier rectangles, and a dashed edge drawn round
7723  the selection.
7724  */
7725  {
7726  if(!MMoveTrackSelFlag)
7727  {
7728  TrainController->LogEvent("MouseMove + TrackSelecting");
7729  MMoveTrackSelFlag = true;
7730  }
7731  int CurrentHLoc, CurrentVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7732  Track->GetTrackLocsFromScreenPos(2, CurrentHLoc, CurrentVLoc, X, Y);
7733  // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7734  // rightmost point and the VLoc value of the bottommost point
7735  if(CurrentHLoc >= StartHLoc)
7736  {
7737  CurrentHLoc++;
7738  }
7739  else
7740  {
7741  StartHLoc++;
7742  }
7743  if(CurrentVLoc >= StartVLoc)
7744  {
7745  CurrentVLoc++;
7746  }
7747  else
7748  {
7749  StartVLoc++;
7750  }
7751  if(CurrentHLoc - Display->DisplayOffsetH > Utilities->ScreenElementWidth)
7752  {
7754  }
7755  if(CurrentVLoc - Display->DisplayOffsetV > Utilities->ScreenElementHeight)
7756  {
7758  }
7759  if(CurrentHLoc - Display->DisplayOffsetH < 0)
7760  {
7761  CurrentHLoc = Display->DisplayOffsetH;
7762  }
7763  if(CurrentVLoc - Display->DisplayOffsetV < 0)
7764  {
7765  CurrentVLoc = Display->DisplayOffsetV;
7766  }
7767  TRect TempRect(StartHLoc, StartVLoc, CurrentHLoc, CurrentVLoc);
7768  ClearandRebuildRailway(14); // to clear earlier rectangles
7769  Display->PlotDashedRect(0, TempRect);
7770  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
7771  }
7772 
7774  {
7775  if(!MMovePrefDirSelFlag)
7776  {
7777  TrainController->LogEvent("MouseMove + PrefDirSelecting");
7778  MMovePrefDirSelFlag = true;
7779  }
7780 
7781  int CurrentHLoc, CurrentVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7782  Track->GetTrackLocsFromScreenPos(5, CurrentHLoc, CurrentVLoc, X, Y);
7783  // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7784  // rightmost point and the VLoc value of the bottommost point
7785  if(CurrentHLoc >= StartHLoc)
7786  {
7787  CurrentHLoc++;
7788  }
7789  else
7790  {
7791  StartHLoc++;
7792  }
7793  if(CurrentVLoc >= StartVLoc)
7794  {
7795  CurrentVLoc++;
7796  }
7797  else
7798  {
7799  StartVLoc++;
7800  }
7801  if(CurrentHLoc - Display->DisplayOffsetH > Utilities->ScreenElementWidth)
7802  {
7804  }
7805  if(CurrentVLoc - Display->DisplayOffsetV > Utilities->ScreenElementHeight)
7806  {
7808  }
7809  if(CurrentHLoc - Display->DisplayOffsetH < 0)
7810  {
7811  CurrentHLoc = Display->DisplayOffsetH;
7812  }
7813  if(CurrentVLoc - Display->DisplayOffsetV < 0)
7814  {
7815  CurrentVLoc = Display->DisplayOffsetV;
7816  }
7817  TRect TempRect(StartHLoc, StartVLoc, CurrentHLoc, CurrentVLoc);
7818  ClearandRebuildRailway(57); // to clear earlier rectangles
7819  Display->PlotDashedRect(2, TempRect);
7820  Display->Update(); // need to keep this since Update() not called for PlotSmallOutput as too slow
7821  }
7822 
7824  /* [Repeated from MouseDown] - The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
7825  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
7826  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
7827  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
7828  [New] - The same actions apply on MouseMove whether Copy or Cut selected from the menu. The X & Y mouse positions are checked and set to
7829  stay within the display area. Then the current selection H & V positions are stored in NewSelectBitmapHLoc & VLoc.
7830  These change continually while the mouse and the selection are moving, they are only read on MouseUp to retain the position that it then
7831  occupies. Clearand... is called finally to clear earlier selection displays.
7832  */
7833  {
7835  {
7836  TrainController->LogEvent("MouseMove + Copy or CutMoving & SelectPickedUp");
7838  }
7839  if(X < 0)
7840  {
7841  X = 0; // ensure pointer stays within display area
7842  }
7843  if(X > (MainScreen->Width - 1))
7844  {
7845  X = MainScreen->Width - 1;
7846  }
7847  if(Y < 0)
7848  {
7849  Y = 0;
7850  }
7851  if(Y > (MainScreen->Height - 1))
7852  {
7853  Y = MainScreen->Height - 1;
7854  }
7857  ClearandRebuildRailway(15); // plots SelectBitmap at the position given by NewSelectBitmapHLoc & ...VLoc
7858  }
7859 
7861  {
7863  {
7864  TrainController->LogEvent("MouseMove + MoveTextOrGraphic & TextFoundFlag");
7866  }
7868  NewHPos = TextOrUserGraphicGridVal * (div(NewHPos, TextOrUserGraphicGridVal).quot);
7870  NewVPos = TextOrUserGraphicGridVal * (div(NewVPos, TextOrUserGraphicGridVal).quot);
7871 
7872  TextHandler->TextPtrAt(26, TextItem)->HPos = NewHPos;
7873  TextHandler->TextPtrAt(27, TextItem)->VPos = NewVPos;
7875  }
7876 
7878  {
7880  {
7881  TrainController->LogEvent("MouseMove + MoveTextOrGraphic & UserGraphicFoundFlag");
7883  }
7885  NewHPos = TextOrUserGraphicGridVal * (div(NewHPos, TextOrUserGraphicGridVal).quot);
7887  NewVPos = TextOrUserGraphicGridVal * (div(NewVPos, TextOrUserGraphicGridVal).quot);
7888 
7892  }
7893  }
7894  Utilities->CallLogPop(70);
7895  }
7896  catch(const Exception &e)
7897  {
7898  ErrorLog(22, e.Message);
7899  }
7900 }
7901 
7902 // ---------------------------------------------------------------------------
7903 void __fastcall TInterface::MainScreenMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
7904 {
7905 /* [Repeated from MouseDown] - When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
7906  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
7907  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
7908  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
7909  selected rectangle.
7910  [Repeated from MouseMove] - At this point the select starting position has been defined in SelectStartPair, and the current mouse position is defined (wrt whole
7911  railway) in HLoc & VLoc from the screen positions X & Y by GetTrackLocsFromScreenPos. Both are incremented so that the rectangle
7912  includes the current point (if no mouse movement at all occurs then a 1 x 1 rectangle is displayed). Limits are set to prevent the
7913  displayed rectangle extending off screen. Edges are set at 60 & 36 rather than 59 & 35 because the defined rectangle excludes the
7914  rightmost and bottom HLoc & VLoc values, if 59 & 35 were used the right & bottom screen edges wouldn't be reached. A TRect is then
7915  defined from SelectStartPair and the HLoc/VLoc values, Clearand... called to clear earlier rectangles, and a dashed edge drawn round
7916  the selection.
7917  [New] This function can take some time so an hourglass cursor is displayed. The rectangle is fully defined, so the final screen X & Y
7918  values are translated into HLoc & VLoc values (wrt whole railway) and SelectEndPair set using them. The rectangle can be defined in any
7919  direction, so the end points may be before or after the starting points for both horizontal and vertical directions. Therefore the
7920  rectangle that will be used subsequently - SelectRect - is defined from SelectStart and SelectEnd allowing for any direction. Screen
7921  limits are set as during MouseMove, and a dashed edge drawn as before. Then a check is made to see if the final rectangle has any area,
7922  and if not 'Select' mode is kept and the function ends so that a new rectangle can be drawn, otherwise new menu items Cut, Copy & Delete,
7923  are enabled. Now the SelectBitmap is made ready by filling with white prior to the track bitmaps being copied. If this isn't done the
7924  track bitmaps are loaded from the top left hand corner and the rest becomes black - not what is wanted! The SelectVector (defined in
7925  TrackUnit) is then loaded with the elements enclosed by the rectangle, top to bottom and left to right, active track elements first then
7926  inactive track elements. Empty squares are ignored as are default (erased) elements. Now the SelectVector is read and the corresponding
7927  element bitmaps transferred to SelectBitmap in the appropriate positions, then a dashed border added. Finally the cursor is changed back
7928  to an arrow.
7929 */
7930  try
7931  {
7932  TrainController->LogEvent("MainScreenMouseUp," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7933  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseUp," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7934  WholeRailwayMoving = false; // added at v2.1.0
7935  Screen->Cursor = TCursor(-2); // Arrow; (to reset from four arrows when moving) added at v2.1.0
7936  MMoveTrackSelFlag = false;
7937  MMovePrefDirSelFlag = false;
7941 
7943  {
7944  TrainController->LogEvent("MouseUp + TrackSelecting + mbLeftDown");
7945  Screen->Cursor = TCursor(-11); // Hourglass;
7946  int EndHLoc, EndVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7947  Track->GetTrackLocsFromScreenPos(3, EndHLoc, EndVLoc, X, Y); // these values don't allow for offsets so add in later
7948 // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7949 // rightmost point and the VLoc value of the bottommost point
7950  if(EndHLoc >= StartHLoc)
7951  {
7952  EndHLoc++;
7953  }
7954  else
7955  {
7956  StartHLoc++;
7957  }
7958  if(EndVLoc >= StartVLoc)
7959  {
7960  EndVLoc++;
7961  }
7962  else
7963  {
7964  StartVLoc++;
7965  }
7966  if(StartHLoc >= EndHLoc)
7967  {
7968  SelectRect.left = EndHLoc;
7969  SelectRect.right = StartHLoc;
7970  }
7971  else
7972  {
7973  SelectRect.left = StartHLoc;
7974  SelectRect.right = EndHLoc;
7975  }
7976  if(StartVLoc >= EndVLoc)
7977  {
7978  SelectRect.top = EndVLoc;
7979  SelectRect.bottom = StartVLoc;
7980  }
7981  else
7982  {
7983  SelectRect.top = StartVLoc;
7984  SelectRect.bottom = EndVLoc;
7985  }
7987  {
7989  }
7991  {
7993  }
7994  if(SelectRect.left - Display->DisplayOffsetH < 0)
7995  {
7997  }
7998  if(SelectRect.top - Display->DisplayOffsetV < 0)
7999  {
8001  }
8002  Level2TrackMode = AddTrack; // Level1Mode must be TrackMode
8003  SetLevel2TrackMode(69); // add all track elements so area can be filled with an element, must come before PlotDashedRect as calls Clearand...
8004  Level2TrackMode = TrackSelecting; // reset from AddTrack
8008  if((SelectRect.top == SelectRect.bottom) || (SelectRect.left == SelectRect.right))
8009  {
8010  SelectionValid = false;
8012  mbLeftDown = false;
8013  Screen->Cursor = TCursor(-2); // Arrow;
8014  Utilities->CallLogPop(71);
8015  return; // no rectangle
8016  }
8017  else
8018  {
8019  ReselectMenuItem->Enabled = false;
8020  CutMenuItem->Enabled = true;
8021  CopyMenuItem->Enabled = true;
8022  FlipMenuItem->Enabled = true;
8023  MirrorMenuItem->Enabled = true;
8024  RotRightMenuItem->Enabled = true;
8025  RotLeftMenuItem->Enabled = true;
8026  RotateMenuItem->Enabled = true;
8027 
8028 // PasteWithAttributesMenuItem->Enabled = false; //new menu item for v2.2.0 only enabled after cutting (dropped at 2.4.0 as all pastes are with attributes)
8029  DeleteMenuItem->Enabled = true;
8030  if(Track->IsTrackFinished())
8031  {
8032  SelectLengthsMenuItem->Enabled = true; // only permit if finished because reverts to DistanceStart
8033  }
8034  else
8035  {
8036  SelectLengthsMenuItem->Enabled = false; // and that can only be used if track linked
8037  }
8038  SelectBiDirPrefDirsMenuItem->Visible = false;
8039  CheckPrefDirConflictsMenuItem->Visible = false;
8040  CancelSelectionMenuItem->Enabled = true;
8041  // set SelectBitmap
8042  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
8043  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
8044 
8045  // fill it with transparent white (i.e. use Draw) else graphics all plot from top left hand corner
8046  for(int H = 0; H < (SelectBitmap->Width) / 16; H++)
8047  {
8048  for(int V = 0; V < (SelectBitmap->Height) / 16; V++)
8049  {
8050  SelectBitmap->Canvas->Draw(H * 16, V * 16, RailGraphics->bmSolidBgnd);
8051  // NB in above if use bmTransparent it ISN'T transparent, but if use the non-transparent bmSolidBgnd it IS transparent
8052  // presumably superimposing a transparent bitmap onto a transparent bitmap makes the result non-transparent!
8053  }
8054  }
8055 
8057  TTrackElement TempElement; // default element
8058  bool FoundFlag;
8059  //store active elements
8060  for(int x = SelectRect.left; x < SelectRect.right; x++)
8061  {
8062  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
8063  {
8064  int ATVecPos = Track->GetVectorPositionFromTrackMap(2, x, y, FoundFlag);
8065  if(FoundFlag)
8066  {
8067  TempElement = Track->TrackElementAt(440, ATVecPos);
8068  if(TempElement.SpeedTag > 0)
8069  {
8070  Track->SelectPush(TempElement); // don't store erase elements
8071  }
8072  }
8073  }
8074  }
8075  // now store inactive elements
8076  for(int x = SelectRect.left; x < SelectRect.right; x++)
8077  {
8078  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
8079  {
8080  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(2, x, y, FoundFlag);
8081  if(FoundFlag)
8082  {
8083  TempElement = Track->InactiveTrackElementAt(30, IATVecPair.first);
8084  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
8085  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
8086  {
8087  TempElement = Track->InactiveTrackElementAt(31, IATVecPair.second);
8088  Track->SelectPush(TempElement);
8089  }
8090  }
8091  }
8092  }
8093 
8094  //store preferred directions //added at v2.9.0
8095  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
8096  TPrefDirElement TempPrefDirElement;
8098  for(int x = SelectRect.left; x < SelectRect.right; x++)
8099  {
8100  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
8101  {
8102  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(11, x, y, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
8103  if(FoundFlag)
8104  {
8105  if(PrefDirPos0 > -1)
8106  {
8107  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(2, PrefDirPos0);
8108  SelectPrefDir->ExternalStorePrefDirElement(6, TempPrefDirElement);
8109  }
8110  if(PrefDirPos1 > -1)
8111  {
8112  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(3, PrefDirPos1);
8113  SelectPrefDir->ExternalStorePrefDirElement(7, TempPrefDirElement);
8114  }
8115  if(PrefDirPos2 > -1)
8116  {
8117  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(4, PrefDirPos2);
8118  SelectPrefDir->ExternalStorePrefDirElement(8, TempPrefDirElement);
8119  }
8120  if(PrefDirPos3 > -1)
8121  {
8122  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(5, PrefDirPos3);
8123  SelectPrefDir->ExternalStorePrefDirElement(9, TempPrefDirElement);
8124  }
8125  }
8126  }
8127  }
8128 
8129  // store text items
8130  int LowSelectHPos = SelectRect.left * 16;
8131  int HighSelectHPos = SelectRect.right * 16;
8132  int LowSelectVPos = SelectRect.top * 16;
8133  int HighSelectVPos = SelectRect.bottom * 16;
8134  TextHandler->SelectTextVector.clear();
8135  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
8136  {
8137  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
8138  {
8139  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
8140  HighSelectVPos))
8141  {
8142  // have to create a new TextItem in order to create a new Font object
8143  // BUT: only create new items where they don't appear as named location names
8144  // in SelectVector, since those names shouldn't be copied or pasted.
8145  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
8146  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
8147  bool SelectVectorNamedElement = false;
8148  AnsiString SelectTextString; // new at v2.2.0
8149  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
8150  {
8151  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
8152  {
8153  SelectVectorNamedElement = true;
8154  break;
8155  }
8156  }
8157  if(SelectVectorNamedElement) // changed at v2.2.0
8158  {
8159  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
8160  }
8161  else // new at v2.2.0
8162  {
8163  SelectTextString = TextPtr->TextString;
8164  }
8165  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
8166  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
8167  }
8168  }
8169  }
8170  // store graphic items, but first clear SelectGraphicVector
8171  Track->SelectGraphicVector.clear();
8172  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
8173  {
8174  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
8175  UserGraphicPtr++)
8176  {
8177  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) &&
8178  (UserGraphicPtr->VPos >= LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
8179  {
8180  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
8181  }
8182  }
8183  }
8184 // new method - direct copying of existing selection so text included
8185  TRect Dest(0, 0, SelectBitmap->Width, SelectBitmap->Height);
8186  TRect Source(((SelectRect.left - Display->DisplayOffsetH) * 16), ((SelectRect.top - Display->DisplayOffsetV) * 16),
8187  ((SelectRect.right - Display->DisplayOffsetH) * 16), ((SelectRect.bottom - Display->DisplayOffsetV) * 16));
8188  SelectBitmap->Canvas->CopyRect(Dest, MainScreen->Canvas, Source);
8189  SelectionValid = true;
8190  }
8191  Screen->Cursor = TCursor(-2); // Arrow;
8192  }
8193 
8195  {
8196  TrainController->LogEvent("MouseUp + PrefDirSelecting + mbLeftDown");
8197  Screen->Cursor = TCursor(-11); // Hourglass;
8198 
8199  int EndHLoc, EndVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
8200  Track->GetTrackLocsFromScreenPos(6, EndHLoc, EndVLoc, X, Y); // these values don't allow for offsets so add in later
8201 // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
8202 // rightmost point and the VLoc value of the bottommost point
8203  if(EndHLoc >= StartHLoc)
8204  {
8205  EndHLoc++;
8206  }
8207  else
8208  {
8209  StartHLoc++;
8210  }
8211  if(EndVLoc >= StartVLoc)
8212  {
8213  EndVLoc++;
8214  }
8215  else
8216  {
8217  StartVLoc++;
8218  }
8219  if(StartHLoc >= EndHLoc)
8220  {
8221  SelectRect.left = EndHLoc;
8222  SelectRect.right = StartHLoc;
8223  }
8224  else
8225  {
8226  SelectRect.left = StartHLoc;
8227  SelectRect.right = EndHLoc;
8228  }
8229  if(StartVLoc >= EndVLoc)
8230  {
8231  SelectRect.top = EndVLoc;
8232  SelectRect.bottom = StartVLoc;
8233  }
8234  else
8235  {
8236  SelectRect.top = StartVLoc;
8237  SelectRect.bottom = EndVLoc;
8238  }
8240  {
8242  }
8244  {
8246  }
8247  if(SelectRect.left - Display->DisplayOffsetH < 0)
8248  {
8250  }
8251  if(SelectRect.top - Display->DisplayOffsetV < 0)
8252  {
8254  }
8258  if((SelectRect.top == SelectRect.bottom) || (SelectRect.left == SelectRect.right))
8259  {
8261  mbLeftDown = false;
8262  Screen->Cursor = TCursor(-2); // Arrow;
8263  Utilities->CallLogPop(1551);
8264  return; // no rectangle
8265  }
8266  else
8267  {
8268  SelectBiDirPrefDirsMenuItem->Enabled = true;
8269  CheckPrefDirConflictsMenuItem->Enabled = false;
8270  CancelSelectionMenuItem->Enabled = true;
8271  // don't need SelectBitmap for PrefDir selection
8272 
8273  // store active elements in Track->SelectVector, ignore inactive elements
8274  // clear the vector first
8276  TTrackElement TempElement; // default element
8277  bool FoundFlag;
8278  for(int x = SelectRect.left; x < SelectRect.right; x++)
8279  {
8280  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
8281  {
8282  int ATVecPos = Track->GetVectorPositionFromTrackMap(43, x, y, FoundFlag);
8283  if(FoundFlag)
8284  {
8285  TempElement = Track->TrackElementAt(729, ATVecPos);
8286  if(TempElement.SpeedTag > 0)
8287  {
8288  Track->SelectPush(TempElement); // don't store erase elements
8289  }
8290  }
8291  }
8292  }
8293  }
8294  Screen->Cursor = TCursor(-2); // Arrow;
8295  }
8296 
8298  /* [Repeated from MouseDown] - The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
8299  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
8300  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
8301  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
8302  [Repeated from MouseMove] - The same actions apply on MouseMove whether Copy or Cut selected from the menu. The X & Y mouse positions are checked and set to
8303  stay within the display area. Then the current selection H & V positions are stored in NewSelectBitmapHLoc & VLoc.
8304  These change continually while the mouse and the selection are moving, they are only read on MouseUp to retain the position that it then
8305  occupies. Clearand... is called finally to clear earlier selection displays.
8306  [New] - The only action here is to transfer the values of NewSelectBitmapHLoc & VLoc to SelectBitmapHLoc & VLoc so that the selection
8307  stays in the same position (Clearand... checks whether the mouse is moving (both mbLeftDown & SelectPickedUp true) or stopped (either
8308  mbLeftDown or SelectPickedUp false) and uses NewSelectBitmapHLoc & VLoc or SelectBitmapHLoc & SelectBitmapVLoc respectively.
8309  */
8310  {
8311  TrainController->LogEvent("MouseUp + Copy or CutMoving + mbLeftDown + SelectPickedUp");
8314  }
8315  mbLeftDown = false;
8316  Track->CalcHLocMinEtc(11);
8317  Utilities->CallLogPop(72);
8318  }
8319  catch(const Exception &e)
8320  {
8321  ErrorLog(23, e.Message);
8322  }
8323 }
8324 
8325 // ---------------------------------------------------------------------------
8326 
8327 void __fastcall TInterface::MasterClockTimer(TObject *Sender)
8328 {
8329  try
8330  {
8331  // don't call LogEvent here as would occur too often
8332  // have to allow in zoomout mode
8333  if(ErrorLogCalledFlag)
8334  {
8335  return; // don't continue after an error
8336 
8337  }
8338  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MasterClockTimer");
8339  // put counter outside Clock2 as that may be missed
8340  LCResetCounter++;
8341 // this checks LCs every 20 clock ticks (1 sec) & raises barriers if no route & no train present, to avoid delays due to too frequent calls
8342  if(LCResetCounter > 19)
8343  {
8344  LCResetCounter = 0;
8345  }
8347  if(WarningFlashCount > 4)
8348  {
8349  WarningFlashCount = 0;
8350  }
8351  if(WarningFlashCount == 0)
8352  {
8354  }
8355  if(Utilities->CallLog.size() > 50) // use CTRL ALT 2 to see CallLogSize as program operates
8356  {
8357  throw Exception("Warning - Utilities->CallLog contains more than 50 items"); // check before clock stopped
8358  }
8360  // stopped during 'Paused', when modal windows appear - Popup menu & ShowMessage, and at other times
8361  {
8362  // RestartTime is TTClockTime when operation pauses (timetable start time initially),
8363  // BaseTime is CurrentDateTime() when operation restarts
8364 
8365 // clock speed multiplier
8366  double RealTimeDouble = double(TDateTime::CurrentDateTime() - TrainController->BaseTime);
8367  TrainController->TTClockTime = TDateTime(TTClockSpeed * RealTimeDouble) + TrainController->RestartTime;
8368 // TrainController->TTClockTime = TDateTime::CurrentDateTime() - TrainController->BaseTime + TrainController->RestartTime;
8369  }
8370  TotalTicks++;
8372  {
8373  MissedTicks++;
8374  Utilities->CallLogPop(774);
8375  return;
8376  }
8377  Utilities->Clock2Stopped = true; // don't allow overlapping calls
8378  ClockTimer2(0);
8379  Utilities->Clock2Stopped = false;
8380  Utilities->CallLogPop(73);
8381  }
8382  catch(const Exception &e)
8383  {
8384  ErrorLog(24, e.Message);
8385  }
8386 }
8387 
8388 // ---------------------------------------------------------------------------
8389 
8390 void TInterface::ClockTimer2(int Caller)
8391 {
8392 // called every 50mSec
8393  try
8394  {
8395  // have to allow in zoomout mode
8396  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ClockTimer2");
8397 
8398  // dropped at 2.0.0 because RestoreFocusPanel->SetFocus(); hides the help screen
8399  // If a button holds focus then all that is needed is to click the screen and the arrow keys work correctly
8400 
8401 /* Dropped when new .chm help file introduced at v2.0.0 - this hid it after ~20ms. Replaced by a new section in
8402  MainScreenMouseDown where focus restored to screen when click anywhere on screen, allowing navigation keys to
8403  move screen when clicked if focus had been captured by another panel when these keys just cycle through the panel buttons
8404 
8405  bool FocusRestoreAllowedFlag = true; //added at v1.3.0
8406 
8407  if(TextBox->Focused() || DistanceBox->Focused() || SpeedLimitBox->Focused() || LocationNameTextBox->Focused() || MileEdit->Focused() || ChainEdit->Focused() || YardEdit->Focused() ||
8408  SpeedEditBox2->Focused() || LocationNameComboBox->Focused() || AddSubMinsBox->Focused() || SpeedEditBox->Focused() || PowerEditBox->Focused() || OneEntryTimetableMemo->Focused() ||
8409  AddPrefDirButton->Focused()) //Added at v1.3.0. If any of these has focus then they keep it until they release it. AddPrefDirButton is included as it should keep focus
8410  FocusRestoreAllowedFlag = false; //when it has it - eases the setting of PrefDirs, also this button becomes disabled after use so focus returns to Interface naturally
8411 
8412  if(!Focused() && FocusRestoreAllowedFlag && (GetAsyncKeyState(VK_LBUTTON) >= 0) && (GetAsyncKeyState(VK_RBUTTON) >= 0)) //condition added at v1.3.0 to ensure focus returned to
8413  //Interface (so arrow keys work to move screen) & not left at any of the buttons or other Windows controls
8414  //include the Windows API functions to test that the mouse buttons are not down (strictly only need left but user may have mapped the left onto the right so test both) - if not
8415  //tested then don't always respond to button clicks on navigation and other buttons because the focus can be grabbed back from the button by RestoreFocusPanel before the button
8416  //can respond (takes about 200mSec from click to response) a delay is also included to doubly avoid the button losing focus as above
8417  {
8418  ClockTimer2Count++; //doesn't matter what value it starts at on first use, it will soon revert to 0
8419  if(ClockTimer2Count > 10) ClockTimer2Count = 0; //half second delay
8420  if(ClockTimer2Count == 0)
8421  {
8422  RestoreFocusPanel->Visible = true;
8423  RestoreFocusPanel->Enabled = true;
8424  RestoreFocusPanel->BringToFront();
8425  //RestoreFocusPanel->SetFocus(); //to remove focus from anything else
8426  RestoreFocusPanel->Enabled = false; //to remove focus from RestoreFocusPanel & return it to Interface
8427  RestoreFocusPanel->Visible = false;
8428  }
8429  }
8430  else ClockTimer2Count = 0; //reset to 0 so ensure full delay occurs before RestoreFocusPanel grabs focus from anything else
8431 */
8432 
8433  CallLogTickerLabel->Caption = Utilities->CallLog.size(); // diagnostic test function to ensure all CallLogs are popped - visibility
8434  // toggled by 'Ctrl Alt 2' when Interface form has focus
8435 
8436  // set current time
8437  TDateTime Now = TrainController->TTClockTime;
8438 
8439  if(!OAListBox->MouseInClient) // added at v2.7.0 to reset this flag whenever mouse not in OAListBox
8440  {
8442  }
8443  if(!ClipboardChecked)
8444  {
8445  if((Level1Mode == TrackMode) && !SelectionValid && (ClpBrdValid != "RlyClpBrd_Cut") && (ClpBrdValid != "RlyClpBrdCopy"))
8446  // reset the menu for the new app (when !SelectionValid) & don't keep resetting when ClpBrdValid
8447  //before 2.10.0 one '&' was missing before '(ClpBrdValid != "RlyClpBrd_Cut")' making it into an address which would always be > 0 i.e.true
8448  {
8449  SetTrackModeEditMenu(2); // to reset the menu in case select a new app for pasting
8450  ClipboardChecked = true;
8451  }
8452  }
8456  {
8458  }
8459  if(OperatorActionPanel->Visible)
8460  {
8462  }
8465  {
8466  TrainController->OpActionPanelHintDelayCounter = 60; // new at v2.2.0
8467  }
8468  TrainController->RandomFailureCounter++; // new at v2.4.0 counts up for 53 seconds then resets
8470  {
8472  }
8473 // Update Displayed Clock - resets to 0 at 96hours
8475 
8476 // Below added at v2.1.0 to ensure WholeRailwayMoving flag reset when not moving (when rh mouse button up) as sometimes misses
8477 // MouseUp events, probably due to a clash between a moving event and a mouse up event. Note that checks that both mouse buttons are up because
8478 // function only checks the physical buttons, not the logical buttons. Most sig bit of return value set form key down.
8479  if(WholeRailwayMoving && (GetAsyncKeyState(VK_LBUTTON) >= 0) && (GetAsyncKeyState(VK_RBUTTON) >= 0))
8480  {
8481  WholeRailwayMoving = false;
8482  Screen->Cursor = TCursor(-2); // Arrow
8483  }
8484 // save session if required
8485  if(SaveSessionFlag)
8486  {
8487  SaveSession(0);
8488  SaveSessionFlag = false;
8489  }
8490 // load session if required
8491  if(LoadSessionFlag)
8492  {
8493  if(ClearEverything(3))
8494  {
8495  LoadSession(0);
8496  }
8497  LoadSessionFlag = false;
8498  }
8499 // check if any LCs need barriers raising
8500 
8502  {
8504  {
8505  for(int x = Track->BarriersDownVector.size() - 1; x >= 0; x--) // iterate downwards because erase element
8506  {
8507  bool TrainPresent = false;
8509  Track->BarriersDownVector.at(x).VLoc, ConstructRoute->SearchVector, TrainPresent)) // returns true for route (set or being set) or train, and TrainPresent true if train on LC
8510  {
8511  if(TrainPresent)
8512  {
8513  Track->BarriersDownVector.at(x).ReducedTimePenalty = true;
8514 // to allow 3 mins before time penalty starts to clock up, if no train passes then no time allowance
8515  }
8516  }
8517  else
8518  {
8519  if(Track->BarriersDownVector.at(x).TypeOfRoute != 2) // added at v2.6.0 for manual LC operation
8520  {
8521  Track->LCChangeFlag = true;
8523  // check if have exceeded the allowance (3 minutes for a train having passed or 0 for not) and add it to the overall excess time
8524  TDateTime TempExcessLCDownTime;
8525  if(Track->BarriersDownVector.at(x).ReducedTimePenalty)
8526  {
8527  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime - TDateTime(180.0 / 86400);
8528  }
8529  else
8530  {
8531  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime;
8532  }
8533  if(TempExcessLCDownTime > TDateTime(0))
8534  {
8535  TrainController->ExcessLCDownMins += (double(TempExcessLCDownTime) * 1440);
8536  }
8537  CLC.StartTime = TrainController->TTClockTime; // reset these 3 members
8540  Track->SetLinkedLevelCrossingBarrierAttributes(0, CLC.HLoc, CLC.VLoc, 2); // set attr to 2 for changing state
8541  Track->ChangingLCVector.push_back(CLC);
8542  Track->BarriersDownVector.erase(Track->BarriersDownVector.begin() + x);
8543  }
8544  }
8545  }
8546  }
8547  }
8548 // clear LCChangeFlag if no LCs changing
8549  if(Track->ChangingLCVector.empty())
8550  {
8551  Track->LCChangeFlag = false;
8552  }
8553 // remove any single route elements if operating, but only if not constructing a route, else if extending the single route
8554 // element it may be removed prior to conversion & cause an error
8555 
8556 // note that if a train enters at a continuation and a signal is next but one to the continuation then the route element at that
8557 // signal won't be removed because the train's LagElement is still -1 and trains only remove route elements when LagElement is > -1.
8558 // This also means that a preferred route can't be cancelled as it's under a train, but it's probably not worth adding a patch just for
8559 // this, it shouldn't interfere with operation.
8561  {
8562  bool ElementRemovedFlag = false; // introduced at v0.6 to avoid calling Clearand.... multiple times
8563  for(unsigned int x = 0; x < AllRoutes->AllRoutesSize(); x++)
8564  {
8565  if(AllRoutes->GetFixedRouteAt(187, x).PrefDirSize() == 1)
8566  {
8567  // only allow route element to be removed if not selected for a route start otherwise StartSelectionRouteID will be
8568  // set & will fail at convert
8570  {
8572  // also don't remove if it links two automatic signal routes (reported by Daniel Gill for Darlington via discord on 13/12/20)
8573  // added at v2.6.1
8574  // note that a train will still remove the route element when it reaches it because of the 3rd condition below, but it will be removed when the train
8575  // is half on the preceding element rather than fully on it, in other cases the train has to be fully on the element because the route only becomes a
8576  // single element at that stage
8577  unsigned int LinkFromTVNumber = Track->TrackElementAt(1007, PDE.GetTrackVectorPosition()).Conn[PDE.GetELinkPos()];
8578  unsigned int LinkToTVNumber = Track->TrackElementAt(1008, PDE.GetTrackVectorPosition()).Conn[PDE.GetXLinkPos()];
8579  int RouteNumber1, RouteNumber2, TrainID; // not used
8580  if((AllRoutes->GetRouteTypeAndNumber(37, LinkFromTVNumber, PDE.GetELinkPos(), RouteNumber1) != TAllRoutes::AutoSigsRoute) ||
8581  (AllRoutes->GetRouteTypeAndNumber(38, LinkToTVNumber, PDE.GetXLinkPos(), RouteNumber2) != TAllRoutes::AutoSigsRoute) ||
8582  (Track->TrackElementAt(1009, LinkFromTVNumber).TrainIDOnElement > -1))
8583  // don't need to test for it being a bridge as then LinkFromTVNumber can't be
8584  // an autosigs route
8585  {
8586  AllRoutes->RemoveRouteElement(20, PDE.HLoc, PDE.VLoc, PDE.GetELink());
8587  ElementRemovedFlag = true;
8588  TrainController->LogEvent("SingleRouteElementRemoved, H = " + AnsiString(PDE.HLoc) + ", V = " + AnsiString(PDE.VLoc));
8589  }
8590  }
8591  }
8592  }
8593  if(!Display->ZoomOutFlag && ElementRemovedFlag)
8594  {
8596  }
8597  // if zoomed out ignore, will display correctly when zoom in
8598  // if leave the Zoomout condition out then the zoom out will spontaneously cancel and the track won't display because
8599  // PlotOutput returns if zoomed out, and the zoom out flag isn't reset until the end of Clearand.....
8600  // this was moved outside the for.. next.. loop in v0.6 as it could be called multiple times and slowed down operation (noticeable with a fast clock)
8601  }
8602 // stop clock if hover over a warning
8603  bool WH1 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog1->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog1->Width + OutputLog1->Left))
8604  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog1->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog1->Height + OutputLog1->Top))
8605  && OutputLog1->Caption != "";
8606  bool WH2 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog2->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog2->Width + OutputLog2->Left))
8607  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog2->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog2->Height + OutputLog2->Top))
8608  && OutputLog2->Caption != "";
8609  bool WH3 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog3->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog3->Width + OutputLog3->Left))
8610  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog3->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog3->Height + OutputLog3->Top))
8611  && OutputLog3->Caption != "";
8612  bool WH4 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog4->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog4->Width + OutputLog4->Left))
8613  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog4->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog4->Height + OutputLog4->Top))
8614  && OutputLog4->Caption != "";
8615  bool WH5 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog5->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog5->Width + OutputLog5->Left))
8616  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog5->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog5->Height + OutputLog5->Top))
8617  && OutputLog5->Caption != "";
8618  bool WH6 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog6->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog6->Width + OutputLog6->Left))
8619  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog6->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog6->Height + OutputLog6->Top))
8620  && OutputLog6->Caption != "";
8621  bool WH7 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog7->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog7->Width + OutputLog7->Left))
8622  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog7->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog7->Height + OutputLog7->Top))
8623  && OutputLog7->Caption != "";
8624  bool WH8 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog8->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog8->Width + OutputLog8->Left))
8625  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog8->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog8->Height + OutputLog8->Top))
8626  && OutputLog8->Caption != "";
8627  bool WH9 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog9->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog9->Width + OutputLog9->Left))
8628  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog9->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog9->Height + OutputLog9->Top))
8629  && OutputLog9->Caption != "";
8630  bool WH10 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog10->Left) &&
8631  (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog10->Width + OutputLog10->Left)) && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog10->Top) &&
8632  (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog10->Height + OutputLog10->Top)) && OutputLog10->Caption != "";
8633 
8634  if(WH1 || WH2 || WH3 || WH4 || WH5 || WH6 || WH7 || WH8 || WH9 || WH10)
8635  {
8636  if(!WarningHover)
8637  {
8638  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
8640  WarningHover = true;
8641  }
8642  }
8643  else if(WarningHover)
8644  {
8645  WarningHover = false;
8646  TrainController->BaseTime = TDateTime::CurrentDateTime();
8648  }
8649 // development panel - visibility toggled by 'Ctrl Alt 3' when Interface form has focus
8650  if(DevelopmentPanel->Visible)
8651  {
8652  int Position;
8653  TTrackElement TrackElement;
8654  AnsiString Type[15] =
8655  {
8656  "Simple", "Crossover", "Points", "Buffers", "Bridge", "SignalPost", "Continuation", "Platform", "GapJump", "FootCrossing", "Unused", "Concourse",
8657  "Parapet", "NamedNonStationLocation", "Erase"
8658  };
8659 
8660  int ScreenX = Mouse->CursorPos.x - MainScreen->ClientOrigin.x;
8661  int ScreenY = Mouse->CursorPos.y - MainScreen->ClientOrigin.y;
8662  int HLoc, VLoc;
8663  AnsiString MouseStr = "Posx: " + AnsiString(ScreenX) + "; Posy: " + AnsiString(ScreenY);
8664  DevelopmentPanel->Caption = CurDir + " " + MouseStr;
8665  Track->GetTrackLocsFromScreenPos(7, HLoc, VLoc, ScreenX, ScreenY);
8666  if(Track->FindNonPlatformMatch(1, HLoc, VLoc, Position, TrackElement))
8667  {
8668  DevelopmentPanel->Caption = MouseStr + "; TVPos: " + AnsiString(Position) + "; H: " + AnsiString(HLoc) + "; V: " + AnsiString(VLoc) +
8669  "; SpTg: " + AnsiString(TrackElement.SpeedTag) + "; Type: " + Type[TrackElement.TrackType] + "; Att: " + AnsiString(TrackElement.Attribute)
8670  + "; TrID: " + AnsiString(TrackElement.TrainIDOnElement) + "; TrID01: " + AnsiString(TrackElement.TrainIDOnBridgeTrackPos01) +
8671  "; TrID23: " + AnsiString(TrackElement.TrainIDOnBridgeTrackPos23) + "; " + TrackElement.LocationName + "; " +
8672  TrackElement.ActiveTrackElementName;
8673 // + "; OAHintCtr: " + TrainController->OpActionPanelHintDelayCounter;
8674  }
8675  }
8676  if(Level1Mode == TimetableMode)
8677  {
8678 /* These are for Shift Key shortcuts. Unless 'Click()' execution occurs after the key is pressed Windows stores the key until after any code is executed then selects
8679 the timetable entry that begins with the letter corresponding to the key. See DevHistory.txt for the version at v2.5.0 for details.
8680 
8681 First make sure the selected entry is the Highlighted entry, but only if both mouse buttons are up, to make sure AllEntriesTTListBoxMouseUp runs first or TopIndex
8682 likely to be set to the wrong position since when ...Selected... runs it sets TopIndex accordingly. Then when ...MouseUp runs it will use the wrong value and select
8683 the entry that the mouse is now on rather than the one that was chosen.
8684 Later addition: Set member variable AllEntriesTTListBox->TopIndex here if any flag set so when Copy or any other key function runs the top index is correct
8685 */
8686  if((GetKeyState(VK_LBUTTON) >= 0) && (GetKeyState(VK_RBUTTON) >= 0) && (TTCurrentEntryPtr > 0))
8687  // high order bit set to 1 when button down, so arithmetically it is negative
8688  {
8689  // TTCurrentEntryPtr == 0 when create a timetable
8690  AllEntriesTTListBox->Selected[TTCurrentEntryPtr - TimetableEditVector.begin()] = true;
8691  }
8692  if(AnyTTKeyFlagSet()) // true if any of the below flags set
8693  {
8694  AllEntriesTTListBox->TopIndex = AllEntriesTTListBoxTopPosition; // reset it to the value before the key press changes it (see FormKeyDown)
8695  }
8697  {
8698  PreviousTTEntryButton->Click();
8699  SetTopIndex(0);
8700  PreviousTTEntryKeyFlag = false;
8701  }
8702  else if(NextTTEntryKeyFlag)
8703  {
8704  NextTTEntryButton->Click();
8705  SetTopIndex(1);
8706  NextTTEntryKeyFlag = false;
8707  }
8708  else if(MoveTTEntryUpKeyFlag)
8709  {
8710  MoveTTEntryUpButton->Click();
8711  SetTopIndex(2);
8712  MoveTTEntryUpKeyFlag = false;
8713  }
8714  else if(MoveTTEntryDownKeyFlag)
8715  {
8716  MoveTTEntryDownButton->Click();
8717  SetTopIndex(3);
8718  MoveTTEntryDownKeyFlag = false;
8719  }
8720  else if(CopyTTEntryKeyFlag)
8721  {
8722  CopyTTEntryButton->Click();
8723  SetTopIndex(4);
8724  CopyTTEntryKeyFlag = false;
8725  }
8726  else if(CutTTEntryKeyFlag)
8727  {
8728  CutTTEntryButton->Click();
8729  SetTopIndex(5);
8730  CutTTEntryKeyFlag = false;
8731  }
8732  else if(PasteTTEntryKeyFlag)
8733  {
8734  PasteTTEntryButton->Click();
8735  SetTopIndex(6);
8736  PasteTTEntryKeyFlag = false;
8737  }
8738  else if(DeleteTTEntryKeyFlag)
8739  {
8740  DeleteTTEntryButton->Click();
8741  SetTopIndex(7);
8742  DeleteTTEntryKeyFlag = false;
8743  }
8744  else if(NewTTEntryKeyFlag)
8745  {
8746  NewTTEntryButton->Click();
8747  SetTopIndex(8);
8748  NewTTEntryKeyFlag = false;
8749  }
8750  else if(AZOrderKeyFlag)
8751  {
8752  AZOrderButton->Click();
8753  SetTopIndex(9);
8754  AZOrderKeyFlag = false;
8755  }
8757  {
8758  TTServiceSyntaxCheckButton->Click();
8759  SetTopIndex(12);
8761  }
8762  else if(ValidateTimetableKeyFlag)
8763  {
8764  ValidateTimetableButton->Click();
8765  SetTopIndex(13);
8766  ValidateTimetableKeyFlag = false;
8767  }
8768  else if(SaveTTKeyFlag)
8769  {
8770  SaveTTButton->Click();
8771  SetTopIndex(14);
8772  SaveTTKeyFlag = false;
8773  }
8774  else if(SaveTTAsKeyFlag)
8775  {
8776  SaveTTAsButton->Click();
8777  SetTopIndex(15);
8778  SaveTTAsKeyFlag = false;
8779  }
8780  else if(RestoreTTKeyFlag)
8781  {
8782  RestoreTTButton->Click();
8783  SetTopIndex(16);
8784  RestoreTTKeyFlag = false;
8785  }
8786  else if(ExportTTKeyFlag)
8787  {
8788  ExportTTButton->Click();
8789  SetTopIndex(17);
8790  ExportTTKeyFlag = false;
8791  }
8792  else if(ConflictAnalysisKeyFlag)
8793  {
8794  ConflictAnalysisButton->Click();
8795  SetTopIndex(18);
8796  ConflictAnalysisKeyFlag = false;
8797  }
8798 // highlight timetable entry if in tt mode (have to call this regularly so will scroll with the listbox)
8799  if(!TimetableEditVector.empty() && (TTCurrentEntryPtr > 0))
8800  {
8802  }
8803  else
8804  {
8806  }
8807  }
8808 // set cursor
8810  {
8811  if(!TempCursorSet)
8812  {
8813  TempCursor = Screen->Cursor;
8814  TempCursorSet = true;
8815  }
8816  Screen->Cursor = TCursor(-11); // Hourglass
8817  }
8818  else
8819  {
8820  if(TempCursorSet)
8821  {
8822  Screen->Cursor = TempCursor;
8823  TempCursorSet = false;
8824  }
8825  }
8826  if(Level2OperMode == Operating)
8827  {
8828  TrainController->Operate(0); // ensure this called AFTER the single element route removal to ensure any single elements removed
8829  // prior to CallingOnAllowed being called (in UpdateTrain) as that sets a route from the stop signal
8831  {
8832  UpdateOperatorActionPanel(0); // new at v2.2.0 to update panel when train OpTimeToAct updated (updated earlier)
8833  }
8834  TrainController->SignallerTrainRemovedOnAutoSigsRoute = false; // added at v1.3.0 to ensure doesn't persist beyond one call
8835  }
8836 
8837  else if((Level2OperMode == Paused) || (Level2OperMode == PreStart)) // added at v2.5.0 to show actions due after a session file reloaded
8838  { // modified at v3.0.0 to add PreStart
8840  {
8841  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
8842  {
8844  }
8847  }
8848  }
8849 // plot trains in ZoomOut mode & flash trains where attention needed alternately on & off at each call
8850 // by examining Flash
8851  if((Level1Mode == OperMode) && (Display->ZoomOutFlag))
8852  {
8854  }
8855 //deal with any manual LCs with barriers down in zoomout mode - these flash as reminder that need to re-open
8856 
8858  for(unsigned int x = 0; x < Track->BarriersDownVector.size(); x++)
8859  {
8860  if((Track->BarriersDownVector.at(x).BarrierState == TTrack::Down) && (Track->BarriersDownVector.at(x).TypeOfRoute == 2))
8861  {
8862  //manual crossing down, but maybe a route across it
8863  bool TrainPresent; //not used outside function
8865  ConstructRoute->SearchVector, TrainPresent)) //no warning raised if a route or train present
8866  {
8869  {
8871  RailGraphics->smLC, Display); //smLC
8872  }
8873  else if((WarningFlashCount == 0) && !WarningFlash && Display->ZoomOutFlag)
8874  {
8876  RailGraphics->smSolidBgnd, Display); //SMOrange
8877  }
8878  }
8879  }
8880  }
8881 
8882 // Deal with any flashing graphics
8884  {
8885  FlashingGraphics(0, Now); // only call when WarningFlash changes
8886  if(Level1Mode == OperMode)
8887  {
8888  if(WarningFlash)
8889  {
8891  {
8892  CrashImage->Visible = true;
8893  }
8895  {
8896  DerailImage->Visible = true;
8897  }
8899  {
8900  SPADImage->Visible = true;
8901  }
8903  {
8904  TrainFailedImage->Visible = true;
8905  }
8907  {
8908  CallOnImage->Visible = true;
8909  }
8911  {
8912  SignalStopImage->Visible = true;
8913  }
8915  {
8916  BufferAttentionImage->Visible = true;
8917  }
8918  if(ManualLCDownAttentionWarning) //added at v2.9.0
8919  {
8920  ManualLCDownImage->Visible = true;
8921  }
8922  }
8923  else
8924  {
8925  CrashImage->Visible = false;
8926  DerailImage->Visible = false;
8927  SPADImage->Visible = false;
8928  TrainFailedImage->Visible = false;
8929  CallOnImage->Visible = false;
8930  SignalStopImage->Visible = false;
8931  BufferAttentionImage->Visible = false;
8932  ManualLCDownImage->Visible = false;
8933  }
8934  }
8935  else
8936  {
8937  CrashImage->Visible = false;
8938  DerailImage->Visible = false;
8939  SPADImage->Visible = false;
8940  TrainFailedImage->Visible = false;
8941  CallOnImage->Visible = false;
8942  SignalStopImage->Visible = false;
8943  BufferAttentionImage->Visible = false;
8945  }
8946  } // if(WarningFlashCount == 0)
8947 
8948  // set buttons etc as appropriate
8950  // if forced route cancellation flag set redisplay to clear the cancelled route
8952  {
8954  AllRoutes->RebuildRailwayFlag = false;
8955  }
8956  // deal with approach locking
8958  // deal with ContinuationAutoSigList
8960  // FloatingLabel function
8961  if((TrackInfoOnOffMenuItem->Caption == "Hide") || (TrainStatusInfoOnOffMenuItem->Caption == "Hide Status") ||
8962  (TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable"))
8963  {
8964  TrackTrainFloat(0);
8965  }
8966  else
8967  {
8968  FloatingPanel->Visible = false;
8969  }
8970  // PerformanceLog check function
8971 /*
8972  if(IsPerformancePanelObscuringFloatingLabel(0) && (ShowPerformancePanel))
8973  {
8974  PerformancePanel->Visible = false;
8975  }
8976  else
8977  {
8978 */
8980  {
8981  PerformancePanel->Visible = true;
8982  }
8983  else
8984  {
8985  PerformancePanel->Visible = false;
8986  }
8988  {
8989  OperatorActionPanel->Visible = true;
8990  }
8991  else
8992  {
8993  OperatorActionPanel->Visible = false;
8994  }
8995 // }
8996 
8997  // check if a moving train is present on a route-under-construction start element & cancel it if so
8998  if(RouteMode == RouteContinuing)
8999  {
9000  bool FoundFlag;
9001  int RouteStartVecPos;
9002  if(AutoSigsFlag)
9003  {
9005  FoundFlag);
9006  }
9007  else if(PreferredRoute) // added at v2.7.0, was ConsecSignalsRoute
9008  {
9009  RouteStartVecPos = Track->GetVectorPositionFromTrackMap(8, (SigRouteStartMarker->GetHPos()) / 16, (SigRouteStartMarker->GetVPos()) / 16,
9010  FoundFlag);
9011  }
9012  else
9013  {
9015  FoundFlag);
9016  }
9017  if(FoundFlag && (RouteStartVecPos > -1))
9018  {
9019  TTrackElement TrackElement = Track->TrackElementAt(485, RouteStartVecPos);
9020  if(TrackElement.TrainIDOnElement > -1)
9021  {
9022  if(!(TrainController->TrainVectorAtIdent(2, TrackElement.TrainIDOnElement).Stopped()))
9023  {
9025  // replot train as above erases the front element of the train
9027  }
9028  }
9029  }
9030  }
9031  Utilities->CallLogPop(81);
9032  }
9033  catch(const Exception &e)
9034  {
9035  ErrorLog(25, e.Message);
9036  }
9037 }
9038 
9039 // ---------------------------------------------------------------------------
9040 
9041 void __fastcall TInterface::CallingOnButtonClick(TObject *Sender)
9042 {
9043  try
9044  {
9045  TrainController->LogEvent("CallingOnButtonClick");
9046  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CallingOnButtonClick");
9047  if(CallingOnButton->Down)
9048  {
9049  // CallingOnButton->Down = true;
9050  InfoPanel->Visible = true;
9051  InfoPanel->Caption = "CALLING ON: Select signal for call on";
9052  }
9053  else
9054  {
9055  // CallingOnButton->Down = false;
9057  }
9058  AutoRouteStartMarker->PlotOriginal(29, Display); // if overlay not plotted will ignore
9059  SigRouteStartMarker->PlotOriginal(30, Display); // if overlay not plotted will ignore
9060  NonSigRouteStartMarker->PlotOriginal(31, Display); // if overlay not plotted will ignore
9061  CallingOnButton->Enabled = false;
9062 // added at v1.3.0 to ensure doesn't retain focus - will be re-enabled during ClockTimer2 (in SetSaveMenuAndButtons) if required
9063  Utilities->CallLogPop(82);
9064  }
9065  catch(const Exception &e)
9066  {
9067  ErrorLog(26, e.Message);
9068  }
9069 }
9070 
9071 // ---------------------------------------------------------------------------
9072 void __fastcall TInterface::ScreenLeftButtonClick(TObject *Sender)
9073 {
9074  try
9075  {
9076  // have to allow in zoomout mode
9077  TrainController->LogEvent("ScreenLeftButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9078  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenLeftButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9079  Screen->Cursor = TCursor(-11); // Hourglass;
9080  ScreenLeftButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
9081  if(!Display->ZoomOutFlag)
9082  {
9083  if(CtrlKey)
9084  {
9085  Display->DisplayOffsetH -= 2;
9086  }
9087  else if(ShiftKey)
9088  {
9090  }
9091  else
9092  {
9094  }
9097  {
9099  }
9100  }
9101  else
9102  {
9103  if(CtrlKey)
9104  {
9106  }
9107  else if(ShiftKey)
9108  {
9110  }
9111  else
9112  {
9114  }
9115  Display->ClearDisplay(0);
9118  {
9119  Track->PlotSmallRedGap(0);
9120  }
9121  }
9122  ScreenLeftButton->Enabled = true;
9123  Screen->Cursor = TCursor(-2); // Arrow
9124  Utilities->CallLogPop(83);
9125  }
9126  catch(const Exception &e)
9127  {
9128  ErrorLog(27, e.Message);
9129  }
9130 }
9131 // ---------------------------------------------------------------------------
9132 
9133 void __fastcall TInterface::ScreenRightButtonClick(TObject *Sender)
9134 {
9135  try
9136  {
9137  // have to allow in zoomout mode
9138  TrainController->LogEvent("ScreenRightButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9139  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenRightButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9140  Screen->Cursor = TCursor(-11); // Hourglass;
9141  ScreenRightButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
9142  if(!Display->ZoomOutFlag)
9143  {
9144  if(CtrlKey)
9145  {
9146  Display->DisplayOffsetH += 2;
9147  }
9148  else if(ShiftKey)
9149  {
9151  }
9152  else
9153  {
9155  }
9158  {
9160  }
9161  }
9162  else
9163  {
9164  if(CtrlKey)
9165  {
9167  }
9168  else if(ShiftKey)
9169  {
9171  }
9172  else
9173  {
9175  }
9176  Display->ClearDisplay(1);
9179  {
9180  Track->PlotSmallRedGap(1);
9181  }
9182  }
9183  ScreenRightButton->Enabled = true;
9184  Screen->Cursor = TCursor(-2); // Arrow
9185  Utilities->CallLogPop(84);
9186  }
9187  catch(const Exception &e)
9188  {
9189  ErrorLog(28, e.Message);
9190  }
9191 }
9192 // ---------------------------------------------------------------------------
9193 
9194 void __fastcall TInterface::ScreenDownButtonClick(TObject *Sender)
9195 {
9196  try
9197  {
9198  // have to allow in zoomout mode
9199  TrainController->LogEvent("ScreenDownButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9200  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenDownButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9201  Screen->Cursor = TCursor(-11); // Hourglass;
9202  ScreenDownButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
9203  // BUT - it does prevent it from retaining focus - so can use the cursor keys to scroll the display without being captured by the buttons
9204  if(!Display->ZoomOutFlag)
9205  {
9206  if(CtrlKey)
9207  {
9208  Display->DisplayOffsetV += 2;
9209  }
9210  else if(ShiftKey)
9211  {
9213  }
9214  else
9215  {
9217  }
9220  {
9222  }
9223  }
9224  else
9225  {
9226  if(CtrlKey)
9227  {
9229  }
9230  else if(ShiftKey)
9231  {
9233  }
9234  else
9235  {
9237  }
9238  Display->ClearDisplay(2);
9241  {
9242  Track->PlotSmallRedGap(2);
9243  }
9244  }
9245  ScreenDownButton->Enabled = true;
9246  Screen->Cursor = TCursor(-2); // Arrow
9247  Utilities->CallLogPop(85);
9248  }
9249  catch(const Exception &e)
9250  {
9251  ErrorLog(29, e.Message);
9252  }
9253 }
9254 // ---------------------------------------------------------------------------
9255 
9256 void __fastcall TInterface::ScreenUpButtonClick(TObject *Sender)
9257 {
9258  try
9259  {
9260  // have to allow in zoomout mode
9261  TrainController->LogEvent("ScreenUpButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9262  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenUpButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9263  Screen->Cursor = TCursor(-11); // Hourglass;
9264  ScreenUpButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
9265  if(!Display->ZoomOutFlag)
9266  {
9267  if(CtrlKey)
9268  {
9269  Display->DisplayOffsetV -= 2;
9270  }
9271  else if(ShiftKey)
9272  {
9274  }
9275  else
9276  {
9278  }
9281  {
9283  }
9284  }
9285  else
9286  {
9287  if(CtrlKey)
9288  {
9290  }
9291  else if(ShiftKey)
9292  {
9294  }
9295  else
9296  {
9298  }
9299  Display->ClearDisplay(3);
9302  {
9303  Track->PlotSmallRedGap(3);
9304  }
9305  }
9306  ScreenUpButton->Enabled = true;
9307  Screen->Cursor = TCursor(-2); // Arrow
9308  Utilities->CallLogPop(86);
9309  }
9310  catch(const Exception &e)
9311  {
9312  ErrorLog(30, e.Message);
9313  }
9314 }
9315 // ---------------------------------------------------------------------------
9316 
9317 void __fastcall TInterface::ZoomButtonClick(TObject *Sender)
9318 {
9319  try
9320  {
9321  // have to allow in zoomout mode
9322  TrainController->LogEvent("ZoomButtonClick");
9323  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ZoomButtonClick");
9324  Screen->Cursor = TCursor(-11); // Hourglass;
9325  ZoomButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
9326  if(Display->ZoomOutFlag) // i.e resume zoomed in view
9327  {
9328  TrainController->LogEvent("ZoomButtonClick + ZoomOutFlag");
9329 // TLevel2OperMode TempLevel2OperMode = Level2OperMode;
9330  if(Level1Mode == BaseMode)
9331  {
9332  InfoPanel->Visible = false; // reset infopanel in case not set later
9333  InfoPanel->Caption = "";
9334  SetLevel1Mode(18);
9335  }
9336  else if(Level1Mode == TrackMode)
9337  {
9338  InfoPanel->Visible = false; // reset infopanel in case not set later
9339  InfoPanel->Caption = "";
9340  // set edit menu items
9342  SetLevel2TrackMode(33); // revert to earlier track mode from zoom
9343  }
9344  else if(Level1Mode == PrefDirMode)
9345  {
9347  {
9348  SetLevel1Mode(19); // to redisplay infopanel caption "...select start..."
9349  }
9350  else
9351  {
9352  SetLevel2PrefDirMode(4); // revert to PrefDirContinuing PrefDir mode
9353  }
9354  }
9355 // else if(Level1Mode == TrackMode) SetLevel1Mode();//just revert to basic track mode from zoom
9356 // else if(Level1Mode == PrefDirMode) SetLevel1Mode();//just revert to basic PrefDir mode from zoom
9357  else if(Level1Mode == TimetableMode)
9358  {
9359  InfoPanel->Visible = false;
9360  }
9361  // Don't include OperMode or RestartSessionOperMode as they reset the performance file
9362  else if(Level2OperMode == Operating) // similar to SetLevel2OperMode but without resetting BaseTime
9363  {
9364  OperateButton->Enabled = true;
9365  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
9366  ExitOperationButton->Enabled = true;
9368  }
9369  else if(Level2OperMode == Paused) // similar to SetLevel2OperMode but without resetting RestartTime
9370  {
9371  OperateButton->Enabled = true;
9372  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
9373  ExitOperationButton->Enabled = true;
9374  TTClockAdjButton->Enabled = true;
9377  }
9378  else if(Level2OperMode == PreStart)
9379  {
9380  OperateButton->Enabled = true;
9381  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
9382  ExitOperationButton->Enabled = true;
9383  TTClockAdjButton->Enabled = true;
9385  }
9386  Display->ZoomOutFlag = false; // reset this after level modes called so gap flash stays set if set to begin with
9388  ClearandRebuildRailway(43); // need to call this after ZoomOutFlag reset to display track, even if Clearand... already called
9389  // earlier during level mode setting - because until ZoomOutFlag reset PlotOutput plots nothing
9390  }
9391  else // set zoomed out view
9392  {
9393  TrainController->LogEvent("ZoomButtonClick + != ZoomOutFlag");
9394  Display->ZoomOutFlag = true;
9396  FileMenu->Enabled = false;
9397  ModeMenu->Enabled = false;
9398  EditMenu->Enabled = false;
9399  TextBox->Visible = false;
9400  LocationNameTextBox->Visible = false;
9401  TTClockAdjButton->Enabled = false;
9402 // DisablePanelsStoreMainMenuStates();//ensure Display->ZoomOutFlag set true before calling
9403  // start assuming normal view is at centre of ZoomOut & calc excesses at each side
9404  int OVOffH_NVCentre = Display->DisplayOffsetH - (1.5 * Utilities->ScreenElementWidth);
9405 // start zoomout centre at DisplayOffsetH + 30 - zoomout width/2 = -(1.5 * 60)
9406  int LeftExcess = OVOffH_NVCentre - Track->GetHLocMin();
9407  int RightExcess = Track->GetHLocMax() - OVOffH_NVCentre - ((4 * Utilities->ScreenElementWidth) - 1);
9408  if((LeftExcess > 0) && (RightExcess > 0))
9409  {
9410  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre;
9411  }
9412  else if((LeftExcess > 0) && (RightExcess <= 0))
9413  {
9414  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre + ((RightExcess) / (Utilities->ScreenElementWidth / 2)) *
9415  (Utilities->ScreenElementWidth / 2); // normalise to nearest screen
9416  }
9417  else if((LeftExcess <= 0) && (RightExcess > 0))
9418  {
9419  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre - ((LeftExcess) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2);
9420  }
9421  else
9422  {
9423  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre; // no excess at either side, so display in centre
9424 
9425  }
9426  int OVOffV_NVCentre = Display->DisplayOffsetV - (1.5 * Utilities->ScreenElementHeight);
9427  int TopExcess = OVOffV_NVCentre - Track->GetVLocMin();
9428  int BotExcess = Track->GetVLocMax() - OVOffV_NVCentre - ((4 * Utilities->ScreenElementHeight) - 1);
9429  if((TopExcess > 0) && (BotExcess > 0))
9430  {
9431  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre;
9432  }
9433  else if((TopExcess > 0) && (BotExcess <= 0))
9434  {
9435  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre + ((BotExcess) / (Utilities->ScreenElementHeight / 2)) *
9436  (Utilities->ScreenElementHeight / 2); // normalise to nearest half screen
9437  }
9438  else if((TopExcess <= 0) && (BotExcess > 0))
9439  {
9440  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre - ((TopExcess) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2);
9441  }
9442  else
9443  {
9444  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre; // no excess at either side, so display in centre
9445 
9446  }
9447  Display->ClearDisplay(4);
9451  {
9452  Track->PlotSmallRedGap(4);
9453  }
9454  ZoomButton->Glyph->LoadFromResourceName(0, "ZoomIn");
9455  }
9456  Screen->Cursor = TCursor(-2); // Arrow
9457  ZoomButton->Enabled = true; // restore, see above
9458  Utilities->CallLogPop(87);
9459  }
9460  catch(const Exception &e)
9461  {
9462  ErrorLog(31, e.Message);
9463  }
9464 }
9465 // ---------------------------------------------------------------------------
9466 
9467 void __fastcall TInterface::HomeButtonClick(TObject *Sender)
9468 {
9469  try
9470  {
9471  // have to allow in zoomout mode
9472  TrainController->LogEvent("HomeButtonClick");
9473  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",HomeButtonClick");
9474  Screen->Cursor = TCursor(-11); // Hourglass;
9475  HomeButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
9476  if(!Display->ZoomOutFlag) // zoomed in mode
9477  {
9478  TrainController->LogEvent("HomeButtonClick + zoomed in mode");
9482  {
9484  }
9485  }
9486  else
9487  {
9488  // zoomed out mode
9489  // start assuming normal view is at centre of ZoomOut & calc excesses at each side
9490  TrainController->LogEvent("HomeButtonClick + zoomed out mode");
9492  Display->ClearDisplay(9);
9495  {
9496  Track->PlotSmallRedGap(5);
9497  }
9498  }
9499  Screen->Cursor = TCursor(-2); // Arrow
9500  HomeButton->Enabled = true; // restore, see above
9501  Utilities->CallLogPop(88);
9502  }
9503  catch(const Exception &e)
9504  {
9505  ErrorLog(32, e.Message);
9506  }
9507 }
9508 
9509 // ---------------------------------------------------------------------------
9510 void __fastcall TInterface::NewHomeButtonClick(TObject *Sender)
9511 {
9512  try
9513  {
9514  TrainController->LogEvent("NewHomeButtonClick");
9515  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NewHomeButtonClick");
9516  NewHomeButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
9517  if(!Display->ZoomOutFlag) // zoomed in mode
9518  {
9521  ResetChangedFileDataAndCaption(23, false); // false because no major changes made
9522  }
9523  else
9524  {
9527  }
9528  Utilities->CallLogPop(1188);
9529  NewHomeButton->Enabled = true; // restore, see above
9530  }
9531  catch(const Exception &e)
9532  {
9533  ErrorLog(174, e.Message);
9534  }
9535 }
9536 
9537 // ---------------------------------------------------------------------------
9538 void __fastcall TInterface::EditMenuClick(TObject *Sender)
9539 // added at v2.1.0 to allow CTRL+X, CTRL+C & CTRL+V in edit menu (see case BaseMode for more information)
9540 {
9541  try
9542  {
9543  CopyMenuItem->ShortCut = TextToShortCut("Ctrl+C");
9544  CutMenuItem->ShortCut = TextToShortCut("Ctrl+X");
9545  PasteMenuItem->ShortCut = TextToShortCut("Ctrl+V");
9546  }
9547  catch(const Exception &e)
9548  {
9549  ErrorLog(196, e.Message);
9550  }
9551 }
9552 
9553 // ---------------------------------------------------------------------------
9554 void __fastcall TInterface::SelectMenuItemClick(TObject *Sender)
9555 {
9556 // draw a rectangle with the left mouse button, enclosing whole 16 x 16 squares
9557  try
9558  {
9559  TrainController->LogEvent("SelectMenuItemClick");
9560  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectMenuItemClick");
9561  if(Level1Mode == TrackMode)
9562  {
9563  SelectionValid = false;
9565  SetLevel2TrackMode(34);
9567  {
9568  ShowMessage("Please be aware when pasting that anything inside the pasted area will be overwritten.\n\nThis warning will not be shown again.");
9569  PasteWarningSentFlag = true;
9570  }
9571  }
9572  else if(Level1Mode == PrefDirMode)
9573  {
9576  }
9577  Utilities->CallLogPop(1189);
9578  }
9579  catch(const Exception &e)
9580  {
9581  ErrorLog(145, e.Message);
9582  }
9583 }
9584 
9585 // ---------------------------------------------------------------------------
9586 void __fastcall TInterface::ReselectMenuItemClick(TObject *Sender)
9587 {
9588  try
9589  {
9590  TrainController->LogEvent("ReselectMenuItemClick");
9591  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ReselectMenuItemClick");
9592  if((SelectBitmap->Height == 0) || (SelectBitmap->Width == 0))
9593  {
9594  Utilities->CallLogPop(1424);
9595  return;
9596  }
9597  int TLHCH = SelectBitmapHLoc;
9598  int TLHCV = SelectBitmapVLoc;
9599  int BRHCH = TLHCH + (SelectBitmap->Width / 16);
9600  int BRHCV = TLHCV + (SelectBitmap->Height / 16);
9601  TRect NewSelectRect(TLHCH, TLHCV, BRHCH, BRHCV);
9602  SelectRect = NewSelectRect;
9604  // set bitmap to reselected area (may be different if flip or mirror had been selected earlier)
9605  TRect Dest(0, 0, SelectBitmap->Width, SelectBitmap->Height);
9606  TRect Source(((SelectRect.left - Display->DisplayOffsetH) * 16), ((SelectRect.top - Display->DisplayOffsetV) * 16),
9607  ((SelectRect.right - Display->DisplayOffsetH) * 16), ((SelectRect.bottom - Display->DisplayOffsetV) * 16));
9608  SelectBitmap->Canvas->CopyRect(Dest, MainScreen->Canvas, Source);
9609 
9610  SelectionValid = true;
9611  ReselectMenuItem->Enabled = false;
9612  CutMenuItem->Enabled = true;
9613  CopyMenuItem->Enabled = true;
9614  FlipMenuItem->Enabled = true;
9615  MirrorMenuItem->Enabled = true;
9616  RotRightMenuItem->Enabled = true;
9617  RotLeftMenuItem->Enabled = true;
9618  RotateMenuItem->Enabled = true;
9619  PasteMenuItem->Enabled = false;
9620  DeleteMenuItem->Enabled = true;
9621  if(Track->IsTrackFinished())
9622  {
9623  SelectLengthsMenuItem->Enabled = true; // only permit if finished because reverts to DistanceStart
9624  }
9625  else
9626  {
9627  SelectLengthsMenuItem->Enabled = false; // and that can only be used if track linked
9628  }
9629  SelectBiDirPrefDirsMenuItem->Visible = false;
9630  CheckPrefDirConflictsMenuItem->Visible = false;
9631  CancelSelectionMenuItem->Enabled = true;
9632  mbLeftDown = false;
9633  // Level1Mode = TrackMode;
9634  // SetLevel1Mode(68);
9636  SetLevel2TrackMode(47);
9637  Utilities->CallLogPop(1425);
9638  }
9639  catch(const Exception &e)
9640  {
9641  ErrorLog(146, e.Message);
9642  }
9643 }
9644 
9645 // ---------------------------------------------------------------------------
9646 void __fastcall TInterface::CutMenuItemClick(TObject *Sender)
9647 {
9648  try
9649  {
9650  TrainController->LogEvent("CutMenuItemClick");
9651  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CutMenuItemClick");
9652  // Level1Mode = TrackMode;
9653  // SetLevel1Mode(69);
9654  CopySelected = false; // new at v2.8.0
9655  LoadClipboard(0); // new at v2.8.0
9657  SetLevel2TrackMode(35);
9658  Utilities->CallLogPop(1190);
9659  }
9660  catch(const Exception &e)
9661  {
9662  ErrorLog(147, e.Message);
9663  }
9664 }
9665 // ---------------------------------------------------------------------------
9666 
9667 void __fastcall TInterface::CopyMenuItemClick(TObject *Sender)
9668 {
9669  try
9670  {
9671  TrainController->LogEvent("CopyMenuItemClick");
9672  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CopyMenuItemClick");
9673  // Level1Mode = TrackMode;
9674  // SetLevel1Mode(70);
9675  CopySelected = true; // new at v2.8.0
9676  LoadClipboard(1); // new at v2.8.0
9678  SetLevel2TrackMode(36);
9679  Utilities->CallLogPop(1191);
9680  }
9681  catch(const Exception &e)
9682  {
9683  ErrorLog(148, e.Message);
9684  }
9685 }
9686 
9687 // ---------------------------------------------------------------------------
9688 void __fastcall TInterface::FlipMenuItemClick(TObject *Sender)
9689 {
9690  try
9691  {
9692  TrainController->LogEvent("FlipMenuItemClick");
9693  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FlipMenuItemClick");
9694  // reset values in SelectVector
9695  int VerSum = SelectRect.top + SelectRect.bottom - 1;
9696  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9697  {
9698  // Note: (changed again in v2.4.0 to keep attributes) need to change flip, mirror & 180deg functions as only change speedtag without changing anything else.
9699  // This didn't matter before new paste with attributes added at v2.2.0 as a new element was built from the speedtag,
9700  // but now if do a reselect then cut and paste with attributes the wrong graphic is pasted and all other attributes
9701  // are wrong. Need to rebuild a new TrackElement from the new speedtag and use that in the select vector.
9702  // Note that if use Flip, mirror etc then all attributes lost anyway so ok to build a basic element.
9703  int VLoc = VerSum - Track->SelectVectorAt(8, x).VLoc;
9704  int HLoc = Track->SelectVectorAt(7, x).HLoc;
9706  TE.VLoc = VLoc;
9707  TE.HLoc = HLoc;
9708 
9709  TE.ActiveTrackElementName = Track->SelectVectorAt(37, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9711  TE.Length01 = Track->SelectVectorAt(39, x).Length01;
9712  TE.Length23 = Track->SelectVectorAt(40, x).Length23;
9715  TE.SigAspect = Track->SelectVectorAt(43, x).SigAspect;
9716  Track->SelectVectorAt(26, x) = TE;
9717  }
9718 
9719  int FlipLinkArray[10] =
9720  {
9721  0, 7, 8, 9, 4, 5, 6, 1, 2, 3
9722  }; //0 & 5 are never used
9723 
9724  TrainController->LogEvent("Flip-track ok");
9725  // now reset the pref dirs
9726  for(unsigned int x = 0; x < SelectPrefDir->PrefDirSize(); x++)
9727  {
9728  int OriginalHLoc = SelectPrefDir->PrefDirVector.at(x).HLoc; //added at v2.9.1
9729  int OriginalVLoc = SelectPrefDir->PrefDirVector.at(x).VLoc;
9730  int VLoc = VerSum - SelectPrefDir->PrefDirVector.at(x).VLoc;
9731  int HLoc = SelectPrefDir->PrefDirVector.at(x).HLoc;
9732  int ELink = FlipLinkArray[SelectPrefDir->PrefDirVector.at(x).GetELink()];
9733  int XLink = FlipLinkArray[SelectPrefDir->PrefDirVector.at(x).GetXLink()];
9735  //the above line caused errors when Track->GetTrackElementFromAnyTrackMap in RecoverClipboard had Vector passed in by value,
9736  //causing a bad returned value for SpeedTag and other properties. Passing it in by reference fixed it
9737  TPrefDirElement PDE(TE); //this has Link[4]
9738  PDE.HLoc = HLoc;
9739  PDE.VLoc = VLoc;
9740  PDE.SetELink(ELink);
9741  PDE.SetXLink(XLink);
9742  bool ELinkPosFound = false, XLinkPosFound = false; //these ensure that the link pos is set as low as possible for points
9743  for(int y = 0; y < 4; y++) //changed to y at v2.9.1
9744  {
9745  if(!ELinkPosFound && (PDE.Link[y] == ELink))
9746  {
9747  PDE.SetELinkPos(y);
9748  ELinkPosFound = true;
9749  }
9750  if(!XLinkPosFound && (PDE.Link[y] == XLink))
9751  {
9752  PDE.SetXLinkPos(y);
9753  XLinkPosFound = true;
9754  }
9755  }
9756  //set the CheckCount as before - added at v2.9.1
9757  PDE.SetCheckCount(9); //explicitly set to 9 at v2.9.2
9760 
9761  //set the TrackVectorPosition to correspond to the corresponding TrackElement added at v2.9.1
9762  bool FoundFlag = false;
9763  PDE.SetTrackVectorPosition(Track->GetVectorPositionFromTrackMap(61, OriginalHLoc, OriginalVLoc, FoundFlag)); //uses original TV position as TrackMap hasn't changed yet
9764  if(PDE.GetSignedIntTrackVectorPosition() < 0)
9765  {
9766  FoundFlag = false; //probably will be anyway but reset to be sure & test below
9767  }
9769  if(!PDE.EntryExitNumber() || !ELinkPosFound || !XLinkPosFound || !FoundFlag) //error if can't set the number, any link pos not set or !FoundFlag
9770  {
9772  ShowMessage("Unable to re-orientate the preferred directions, these won't be set in the rotated selection");
9773  break;
9774  }
9775  SelectPrefDir->PrefDirVector.at(x) = PDE;
9776  }
9777 
9778  TrainController->LogEvent("Flip-prefdirs ok");
9779  // reset values in SelectTextVector
9780  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(0); x++)
9781  {
9783  // also subtract font height, brings position approximately right
9784  TextItem->VPos = ((VerSum * 16) + 15) - TextItem->VPos - abs(TextItem->Font->Height);
9785  }
9786  TrainController->LogEvent("Flip-text ok");
9787  // reset values in SelectGraphicVector so the midpoint of the graphic flips about the midline of the selection
9788  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9789  {
9790  int MidVPosBeforeFlip = Track->SelectGraphicVector.at(x).VPos + (Track->SelectGraphicVector.at(x).Height) / 2;
9791  int MidVPosAfterFlip = ((VerSum * 16) + 15) - MidVPosBeforeFlip;
9792  int TopPosAfterFlip = MidVPosAfterFlip - (Track->SelectGraphicVector.at(x).Height) / 2;
9793  Track->SelectGraphicVector.at(x).VPos = TopPosAfterFlip;
9794  }
9796  SetLevel2TrackMode(48);
9797  Utilities->CallLogPop(1426);
9798  }
9799  catch(const Exception &e)
9800  {
9801  ErrorLog(149, e.Message);
9802  }
9803 }
9804 
9805 // ---------------------------------------------------------------------------
9806 void __fastcall TInterface::MirrorMenuItemClick(TObject *Sender)
9807 {
9808  try
9809  {
9810  TrainController->LogEvent("MirrorMenuItemClick");
9811  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MirrorMenuItemClick");
9812  // reset values in SelectVector
9813  int HorSum = SelectRect.left + SelectRect.right - 1;
9814  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9815  {
9816  // See note above for FlipMenuItem relating to mods for v2.2.0
9817  int VLoc = Track->SelectVectorAt(22, x).VLoc;
9818  int HLoc = HorSum - Track->SelectVectorAt(6, x).HLoc;
9820  TE.VLoc = VLoc;
9821  TE.HLoc = HLoc;
9822 
9823  TE.ActiveTrackElementName = Track->SelectVectorAt(44, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9825  TE.Length01 = Track->SelectVectorAt(46, x).Length01;
9826  TE.Length23 = Track->SelectVectorAt(47, x).Length23;
9829  TE.SigAspect = Track->SelectVectorAt(50, x).SigAspect;
9830 
9831 // if(Track->SelectVectorAt(28, x).TrackType == SignalPost) TE.SigAspect = Track->SelectVectorAt(29, x).SigAspect;//TrackType will be the same
9832  Track->SelectVectorAt(30, x) = TE;
9833 // Track->SelectVectorAt(, x).HLoc = HorSum - Track->SelectVectorAt(, x).HLoc;
9834 // Track->SelectVectorAt(, x).SpeedTag = Track->MirrorArray[Track->SelectVectorAt(, x).SpeedTag];
9835  }
9836 
9837  int MirrorLinkArray[10] =
9838  {
9839  0, 3, 2, 1, 6, 5, 4, 9, 8, 7
9840  }; //0 & 5 are never used
9841 
9842  TrainController->LogEvent("Mirror-track ok");
9843  // now reset the pref dirs
9844  for(unsigned int x = 0; x < SelectPrefDir->PrefDirSize(); x++)
9845  {
9846  int OriginalHLoc = SelectPrefDir->PrefDirVector.at(x).HLoc; //added at v2.9.1
9847  int OriginalVLoc = SelectPrefDir->PrefDirVector.at(x).VLoc;
9848  int HLoc = HorSum - SelectPrefDir->PrefDirVector.at(x).HLoc;
9849  int VLoc = SelectPrefDir->PrefDirVector.at(x).VLoc;
9850  int ELink = MirrorLinkArray[SelectPrefDir->PrefDirVector.at(x).GetELink()];
9851  int XLink = MirrorLinkArray[SelectPrefDir->PrefDirVector.at(x).GetXLink()];
9853  //the above line caused errors when Track->GetTrackElementFromAnyTrackMap in RecoverClipboard had Vector passed in by value,
9854  //causing a bad returned value for SpeedTag and other properties. Passing it in by reference fixed it
9855  TPrefDirElement PDE(TE); //this has Link[4]
9856  PDE.HLoc = HLoc;
9857  PDE.VLoc = VLoc;
9858  PDE.SetELink(ELink);
9859  PDE.SetXLink(XLink);
9860  bool ELinkPosFound = false, XLinkPosFound = false; //these ensure that the link pos is set as low as possible for points
9861  for(int y = 0; y < 4; y++) //changed to y at v2.9.1
9862  {
9863  if(!ELinkPosFound && (PDE.Link[y] == ELink))
9864  {
9865  PDE.SetELinkPos(y);
9866  ELinkPosFound = true;
9867  }
9868  if(!XLinkPosFound && (PDE.Link[y] == XLink))
9869  {
9870  PDE.SetXLinkPos(y);
9871  XLinkPosFound = true;
9872  }
9873  }
9874  //set the CheckCount as before - added at v2.9.1
9875  PDE.SetCheckCount(9); //explicitly set to 9 at v2.9.2
9878  //set the TrackVectorPosition to correspond to the corresponding TrackElement added at v2.9.1
9879  bool FoundFlag = false;
9880  PDE.SetTrackVectorPosition(Track->GetVectorPositionFromTrackMap(62, OriginalHLoc, OriginalVLoc, FoundFlag)); //uses original TV position as TrackMap hasn't changed yet
9881  if(PDE.GetSignedIntTrackVectorPosition() < 0)
9882  {
9883  FoundFlag = false; //probably will be anyway but reset to be sure & test below
9884  }
9886  if(!PDE.EntryExitNumber() || !ELinkPosFound || !XLinkPosFound || !FoundFlag) //error if can't set the number, any link pos not set or !FoundFlag
9887  {
9889  ShowMessage("Unable to re-orientate the preferred directions, these won't be set in the rotated selection");
9890  break;
9891  }
9892  SelectPrefDir->PrefDirVector.at(x) = PDE;
9893  }
9894 
9895  TrainController->LogEvent("Mirror-PDs ok");
9896  // reset values in SelectTextVector
9897  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(1); x++)
9898  {
9900  // also subtract half font height for each letter of text, brings position approximately right
9901  TextItem->HPos = ((HorSum * 16) + 15) - TextItem->HPos - (TextItem->TextString.Length() * 0.5 * abs(TextItem->Font->Height));
9902  }
9903  TrainController->LogEvent("Mirror-text ok");
9904  // reset values in SelectGraphicVector so the midpoint of the graphic mirrors about the midline of the selection
9905  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9906  {
9907  int MidHPosBeforeMirror = Track->SelectGraphicVector.at(x).HPos + (Track->SelectGraphicVector.at(x).Width) / 2;
9908  int MidHPosAfterMirror = ((HorSum * 16) + 15) - MidHPosBeforeMirror;
9909  int LeftPosAfterMirror = MidHPosAfterMirror - (Track->SelectGraphicVector.at(x).Width) / 2;
9910  if(LeftPosAfterMirror < (SelectRect.left * 16)) // shouldn't go below left but check
9911  {
9912  LeftPosAfterMirror = SelectRect.left * 16;
9913  }
9914  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterMirror;
9915  }
9917  SetLevel2TrackMode(49);
9918  Utilities->CallLogPop(1427);
9919  }
9920  catch(const Exception &e)
9921  {
9922  ErrorLog(150, e.Message);
9923  }
9924 }
9925 
9926 // ---------------------------------------------------------------------------
9927 void __fastcall TInterface::RotateMenuItemClick(TObject *Sender)
9928 {
9929  try
9930  {
9931  TrainController->LogEvent("Rotate180MenuItemClick");
9932  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",Rotate180MenuItemClick");
9933 
9934  // reset values in SelectVector
9935  int HorSum = SelectRect.left + SelectRect.right - 1;
9936  int VerSum = SelectRect.top + SelectRect.bottom - 1;
9937  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9938  {
9939  // See note above for FlipMenuItem relating to mods for v2.2.0
9940  int VLoc = VerSum - Track->SelectVectorAt(23, x).VLoc;
9941  int HLoc = HorSum - Track->SelectVectorAt(36, x).HLoc;
9943  TE.VLoc = VLoc;
9944  TE.HLoc = HLoc;
9945 
9946  TE.ActiveTrackElementName = Track->SelectVectorAt(51, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9948  TE.Length01 = Track->SelectVectorAt(53, x).Length01;
9949  TE.Length23 = Track->SelectVectorAt(54, x).Length23;
9952  TE.SigAspect = Track->SelectVectorAt(57, x).SigAspect;
9953 
9954 // if(Track->SelectVectorAt(32, x).TrackType == SignalPost) TE.SigAspect = Track->SelectVectorAt(33, x).SigAspect; dropped in v2.4.0 for above
9955  Track->SelectVectorAt(34, x) = TE;
9956 // TTrackElement &TempEl = Track->SelectVectorAt(13, x);
9957 // TempEl.HLoc = HorSum - TempEl.HLoc;
9958 // TempEl.VLoc = VerSum - TempEl.VLoc;
9959 // TempEl.SpeedTag = Track->MirrorArray[Track->FlipArray[TempEl.SpeedTag]];
9960  }
9961 
9962  int Rot180LinkArray[10] =
9963  {
9964  0, 9, 8, 7, 6, 5, 4, 3, 2, 1
9965  }; //0 & 5 are never used
9966  TrainController->LogEvent("Rotate-track ok");
9967  // now reset the pref dirs
9968  for(unsigned int x = 0; x < SelectPrefDir->PrefDirSize(); x++)
9969  {
9970  int OriginalHLoc = SelectPrefDir->PrefDirVector.at(x).HLoc; //added at v2.9.1
9971  int OriginalVLoc = SelectPrefDir->PrefDirVector.at(x).VLoc;
9972  int HLoc = HorSum - SelectPrefDir->PrefDirVector.at(x).HLoc;
9973  int VLoc = VerSum - SelectPrefDir->PrefDirVector.at(x).VLoc;
9974  int ELink = Rot180LinkArray[SelectPrefDir->PrefDirVector.at(x).GetELink()];
9975  int XLink = Rot180LinkArray[SelectPrefDir->PrefDirVector.at(x).GetXLink()];
9977  //the above line caused errors when Track->GetTrackElementFromAnyTrackMap in RecoverClipboard had Vector passed in by value,
9978  //causing a bad returned value for SpeedTag and other properties. Passing it in by reference fixed it
9979  TPrefDirElement PDE(TE); //this has Link[4]
9980  PDE.HLoc = HLoc;
9981  PDE.VLoc = VLoc;
9982  PDE.SetELink(ELink);
9983  PDE.SetXLink(XLink);
9984  bool ELinkPosFound = false, XLinkPosFound = false; //these ensure that the link pos is set as low as possible for points
9985  for(int y = 0; y < 4; y++) //changed to y at v2.9.1
9986  {
9987  if(!ELinkPosFound && (PDE.Link[y] == ELink))
9988  {
9989  PDE.SetELinkPos(y);
9990  ELinkPosFound = true;
9991  }
9992  if(!XLinkPosFound && (PDE.Link[y] == XLink))
9993  {
9994  PDE.SetXLinkPos(y);
9995  XLinkPosFound = true;
9996  }
9997  }
9998  //set the CheckCount as before - added at v2.9.1
9999  PDE.SetCheckCount(9); //explicitly set to 9 at v2.9.2
10002  //set the TrackVectorPosition to correspond to the corresponding TrackElement added at v2.9.1
10003  bool FoundFlag = false;
10004  PDE.SetTrackVectorPosition(Track->GetVectorPositionFromTrackMap(63, OriginalHLoc, OriginalVLoc, FoundFlag)); //uses original TV position as TrackMap hasn't changed yet
10005  if(PDE.GetSignedIntTrackVectorPosition() < 0)
10006  {
10007  FoundFlag = false; //probably will be anyway but reset to be sure & test below
10008  }
10010  if(!PDE.EntryExitNumber() || !ELinkPosFound || !XLinkPosFound || !FoundFlag) //error if can't set the number, any link pos not set or !FoundFlag
10011  {
10013  ShowMessage("Unable to re-orientate the preferred directions, these won't be set in the rotated selection");
10014  break;
10015  }
10016  SelectPrefDir->PrefDirVector.at(x) = PDE;
10017  }
10018  TrainController->LogEvent("Rotate-PDs ok");
10019  // reset values in SelectTextVector
10020  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(2); x++)
10021  {
10023  // also subtract half font height for each letter of text, brings position approximately right horizontally
10024  TextItem->HPos = ((HorSum * 16) + 15) - TextItem->HPos - (TextItem->TextString.Length() * 0.5 * abs(TextItem->Font->Height));
10025  // also subtract font height, brings position approximately right vertically
10026  TextItem->VPos = ((VerSum * 16) + 15) - TextItem->VPos - abs(TextItem->Font->Height);
10027  }
10028  TrainController->LogEvent("Rotate-text ok");
10029  // reset flip values in SelectGraphicVector so the midpoint of the graphic flips about the midline of the selection
10030  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
10031  {
10032  int MidVPosBeforeFlip = Track->SelectGraphicVector.at(x).VPos + (Track->SelectGraphicVector.at(x).Height) / 2;
10033  int MidVPosAfterFlip = ((VerSum * 16) + 15) - MidVPosBeforeFlip;
10034  int TopPosAfterFlip = MidVPosAfterFlip - (Track->SelectGraphicVector.at(x).Height) / 2;
10035  if(TopPosAfterFlip < (SelectRect.top * 16)) // shouldn't go above top but check
10036  {
10037  TopPosAfterFlip = SelectRect.top * 16;
10038  }
10039  Track->SelectGraphicVector.at(x).VPos = TopPosAfterFlip;
10040  }
10041  // reset mirror in SelectGraphicVector so the midpoint of the graphic mirrors about the midline of the selection
10042  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
10043  {
10044  int MidHPosBeforeMirror = Track->SelectGraphicVector.at(x).HPos + (Track->SelectGraphicVector.at(x).Width) / 2;
10045  int MidHPosAfterMirror = ((HorSum * 16) + 15) - MidHPosBeforeMirror;
10046  int LeftPosAfterMirror = MidHPosAfterMirror - (Track->SelectGraphicVector.at(x).Width) / 2;
10047  if(LeftPosAfterMirror < (SelectRect.left * 16)) // shouldn't go below left but check
10048  {
10049  LeftPosAfterMirror = SelectRect.left * 16;
10050  }
10051  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterMirror;
10052  }
10053  // Level1Mode = TrackMode;
10054  // SetLevel1Mode(73);
10056  SetLevel2TrackMode(50);
10057  Utilities->CallLogPop(1435);
10058  }
10059  catch(const Exception &e)
10060  {
10061  ErrorLog(151, e.Message);
10062  }
10063 }
10064 // ---------------------------------------------------------------------------
10065 
10066 void __fastcall TInterface::RotRightMenuItemClick(TObject *Sender)
10067 {
10068  try
10069  {
10070  TrainController->LogEvent("RotateRightMenuItemClick");
10071  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RotateRightMenuItemClick");
10072  Screen->Cursor = TCursor(-11); // Hourglass
10073  // check first if a square and if not give message & quit
10074  if((SelectRect.right - SelectRect.left) != (SelectRect.bottom - SelectRect.top))
10075  {
10076  // use left vertical side to make square & keep top lh corner unless rhs would exceed display, in which case use the right vertical & keep to rh corner
10077  int VertSize = SelectRect.bottom - SelectRect.top;
10078  if((SelectRect.left + VertSize - Display->DisplayOffsetH) > Utilities->ScreenElementWidth)
10079  {
10080  // use right hand vertical & make square to left of that
10081  SelectRect.left = SelectRect.right - VertSize;
10082  }
10083  else
10084  {
10085  SelectRect.right = SelectRect.left + VertSize;
10086  }
10089  int button = Application->MessageBox
10090  (L"Original selection adjusted to make it square. 'OK' to keep this selection or 'Cancel' to make a new selection",
10091  L"Left click and hold here to move this message box", MB_OKCANCEL);
10092  if(button == IDCANCEL)
10093  {
10094  ResetSelectRect();
10095  Level1Mode = TrackMode; // call this first to clear everything, then set PrefDir mode
10096  SetLevel1Mode(133);
10098  SetLevel2TrackMode(59);
10100  Screen->Cursor = TCursor(-2); // Arrow
10101  Utilities->CallLogPop(2121);
10102  return;
10103  }
10104  }
10105  // set SelectBitmap (only need the dimensions here as not moving the selection)
10108  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
10109  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
10110 
10111  // store track elements and text in select vectors - have to store here because original selection might well have changed
10113  TTrackElement TempElement; // default element
10114  bool FoundFlag;
10115  for(int x = SelectRect.left; x < SelectRect.right; x++)
10116  {
10117  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
10118  {
10119  int ATVecPos = Track->GetVectorPositionFromTrackMap(57, x, y, FoundFlag);
10120  if(FoundFlag)
10121  {
10122  TempElement = Track->TrackElementAt(959, ATVecPos);
10123  if(TempElement.SpeedTag > 0)
10124  {
10125  Track->SelectPush(TempElement);
10126  }
10127  }
10128  }
10129  }
10130  // now store inactive elements
10131  for(int x = SelectRect.left; x < SelectRect.right; x++)
10132  {
10133  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
10134  {
10135  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(28, x, y, FoundFlag);
10136  if(FoundFlag)
10137  {
10138  TempElement = Track->InactiveTrackElementAt(126, IATVecPair.first);
10139  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
10140  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
10141  {
10142  TempElement = Track->InactiveTrackElementAt(127, IATVecPair.second);
10143  Track->SelectPush(TempElement);
10144  }
10145  }
10146  }
10147  }
10148  TrainController->LogEvent("RotRight-trackstore ok");
10149  //store preferred directions //added at v2.9.0
10150  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
10151  TPrefDirElement TempPrefDirElement;
10153  for(int x = SelectRect.left; x < SelectRect.right; x++)
10154  {
10155  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
10156  {
10157  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(12, x, y, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
10158  if(FoundFlag)
10159  {
10160  if(PrefDirPos0 > -1)
10161  {
10162  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(6, PrefDirPos0);
10163  SelectPrefDir->ExternalStorePrefDirElement(12, TempPrefDirElement);
10164  }
10165  if(PrefDirPos1 > -1)
10166  {
10167  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(7, PrefDirPos1);
10168  SelectPrefDir->ExternalStorePrefDirElement(13, TempPrefDirElement);
10169  }
10170  if(PrefDirPos2 > -1)
10171  {
10172  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(8, PrefDirPos2);
10173  SelectPrefDir->ExternalStorePrefDirElement(14, TempPrefDirElement);
10174  }
10175  if(PrefDirPos3 > -1)
10176  {
10177  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(9, PrefDirPos3);
10178  SelectPrefDir->ExternalStorePrefDirElement(15, TempPrefDirElement);
10179  }
10180  }
10181  }
10182  }
10183  TrainController->LogEvent("RotRight-PDstore ok");
10184  // store text items
10185  int LowSelectHPos = SelectRect.left * 16;
10186  int HighSelectHPos = SelectRect.right * 16;
10187  int LowSelectVPos = SelectRect.top * 16;
10188  int HighSelectVPos = SelectRect.bottom * 16;
10189  TextHandler->SelectTextVector.clear();
10190  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
10191  {
10192  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
10193  {
10194  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos < HighSelectVPos))
10195  {
10196  // have to create a new TextItem in order to create a new Font object
10197  // BUT: only create new items where they don't appear as named location names
10198  // in SelectVector, since those names shouldn't be copied or pasted.
10199  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
10200  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
10201  bool SelectVectorNamedElement = false;
10202  AnsiString SelectTextString; // new at v2.2.0
10203  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
10204  {
10205  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
10206  {
10207  SelectVectorNamedElement = true;
10208  break;
10209  }
10210  }
10211  if(SelectVectorNamedElement) // changed at v2.2.0
10212  {
10213  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
10214  }
10215  else // new at v2.2.0
10216  {
10217  SelectTextString = TextPtr->TextString;
10218  }
10219  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
10220  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
10221  }
10222  }
10223  }
10224  TrainController->LogEvent("RotRight-textstore ok");
10225  // store graphic items, but first clear SelectGraphicVector
10226  Track->SelectGraphicVector.clear();
10227  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
10228  {
10229  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
10230  UserGraphicPtr++)
10231  {
10232  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) && (UserGraphicPtr->VPos >=
10233  LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
10234  {
10235  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
10236  }
10237  }
10238  }
10239  TrainController->LogEvent("RotRight-graphicstore ok");
10240  // now transform the H & V for rh rotate
10241  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
10242  {
10243  int HLoc = SelectRect.bottom - 1 + SelectRect.left - Track->SelectVectorAt(74, x).VLoc;
10244  int VLoc = SelectRect.top - SelectRect.left + Track->SelectVectorAt(75, x).HLoc;
10246  TE.VLoc = VLoc;
10247  TE.HLoc = HLoc;
10248 
10249  TE.ActiveTrackElementName = Track->SelectVectorAt(58, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
10251  TE.Length01 = Track->SelectVectorAt(60, x).Length01;
10252  TE.Length23 = Track->SelectVectorAt(61, x).Length23;
10255  TE.SigAspect = Track->SelectVectorAt(64, x).SigAspect;
10256  Track->SelectVectorAt(65, x) = TE;
10257  }
10258 
10259  int RotRightLinkArray[10] =
10260  {
10261  0, 3, 6, 9, 2, 5, 8, 1, 4, 7
10262  }; //0 & 5 are never used
10263  TrainController->LogEvent("RotRight-trackrotate ok");
10264  // now transform the pref dirs
10265  for(unsigned int x = 0; x < SelectPrefDir->PrefDirSize(); x++)
10266  {
10267  int OriginalHLoc = SelectPrefDir->GetFixedPrefDirElementAt(250, x).HLoc; //added at v2.9.1
10268  int OriginalVLoc = SelectPrefDir->GetFixedPrefDirElementAt(251, x).VLoc;
10269  int HLoc = SelectRect.bottom - 1 + SelectRect.left - OriginalVLoc;
10270  int VLoc = SelectRect.top - SelectRect.left + OriginalHLoc;
10271  int ELink = RotRightLinkArray[SelectPrefDir->GetFixedPrefDirElementAt(252, x).GetELink()];
10272  int XLink = RotRightLinkArray[SelectPrefDir->GetFixedPrefDirElementAt(253, x).GetXLink()];
10274  //the above line caused errors when Track->GetTrackElementFromAnyTrackMap in RecoverClipboard had Vector passed in by value,
10275  //causing a bad returned value for SpeedTag and other properties. Passing it in by reference fixed it
10276  TPrefDirElement PDE(TE); //this has Link[4]
10277  PDE.HLoc = HLoc;
10278  PDE.VLoc = VLoc;
10279  PDE.SetELink(ELink);
10280  PDE.SetXLink(XLink);
10281  bool ELinkPosFound = false, XLinkPosFound = false; //these ensure that the link pos is set as low as possible for points
10282  for(int y = 0; y < 4; y++) //changed to y at v2.9.1
10283  {
10284  if(!ELinkPosFound && (PDE.Link[y] == ELink))
10285  {
10286  PDE.SetELinkPos(y);
10287  ELinkPosFound = true;
10288  }
10289  if(!XLinkPosFound && (PDE.Link[y] == XLink))
10290  {
10291  PDE.SetXLinkPos(y);
10292  XLinkPosFound = true;
10293  }
10294  }
10295  //set the CheckCount as before - added at v2.9.1
10296  PDE.SetCheckCount(9); //explicitly set to 9 at v2.9.2
10299  //set the TrackVectorPosition to correspond to the corresponding TrackElement added at v2.9.1
10300  bool FoundFlag = false;
10301  PDE.SetTrackVectorPosition(Track->GetVectorPositionFromTrackMap(64, OriginalHLoc, OriginalVLoc, FoundFlag)); //uses original TV position as TrackMap hasn't changed yet
10302  if(PDE.GetSignedIntTrackVectorPosition() < 0)
10303  {
10304  FoundFlag = false; //probably will be anyway but reset to be sure & test below
10305  }
10307  if(!PDE.EntryExitNumber() || !ELinkPosFound || !XLinkPosFound || !FoundFlag) //error if can't set the number, any link pos not set or !FoundFlag
10308  {
10310  ShowMessage("Unable to re-orientate the preferred directions, these won't be set in the rotated selection");
10311  break;
10312  }
10313  SelectPrefDir->PrefDirVector.at(x) = PDE;
10314  }
10315  TrainController->LogEvent("RotRight-PDrotate ok");
10316  // reset values in SelectTextVector
10317  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(3); x++)
10318  {
10319 // no point trying to locate text properly as it stays horizontal so will always be wrongly placed, just list all itels vertically at lhs
10320 // & if a lot then some will extend beyond the selection
10322  // also subtract half font height for each letter of text, brings position approximately right horizontally
10323  TextItem->HPos = (SelectRect.left) * 16;
10324  TextItem->VPos = (SelectRect.top + x) * 16;
10325  }
10326  TrainController->LogEvent("RotRight-textrotate ok");
10327  // reset values in SelectGraphicVector
10328  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
10329  {
10330  int MidHPosBeforeRotate = Track->SelectGraphicVector.at(x).HPos + Track->SelectGraphicVector.at(x).Width / 2;
10331  int MidVPosBeforeRotate = Track->SelectGraphicVector.at(x).VPos + Track->SelectGraphicVector.at(x).Height / 2;
10332  int MidHPosAfterRotate = ((SelectRect.bottom * 16) - 1) + (SelectRect.left * 16) - MidVPosBeforeRotate;
10333  int MidVPosAfterRotate = ((SelectRect.top - SelectRect.left) * 16) + MidHPosBeforeRotate;
10334  int LeftPosAfterRotate = MidHPosAfterRotate - (Track->SelectGraphicVector.at(x).Width) / 2;
10335  int TopPosAfterRotate = MidVPosAfterRotate - (Track->SelectGraphicVector.at(x).Height) / 2;
10336  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterRotate;
10337  Track->SelectGraphicVector.at(x).VPos = TopPosAfterRotate;
10338  }
10339  Screen->Cursor = TCursor(-2); // Arrow
10341  SetLevel2TrackMode(60);
10342  Utilities->CallLogPop(2122);
10343  }
10344  catch(const Exception &e)
10345  {
10346  ErrorLog(205, e.Message);
10347  }
10348 }
10349 
10350 // ---------------------------------------------------------------------------
10351 
10352 void __fastcall TInterface::RotLeftMenuItemClick(TObject *Sender)
10353 {
10354  try
10355  {
10356  TrainController->LogEvent("RotateLeftMenuItemClick");
10357  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RotateLeftMenuItemClick");
10358  Screen->Cursor = TCursor(-11); // Hourglass;
10359  // check first if a square and if not give message & quit
10360  if((SelectRect.right - SelectRect.left) != (SelectRect.bottom - SelectRect.top))
10361  {
10362  // use left vertical side to make square & keep top lh corner unless rhs would exceed display, in which case use the right vertical & keep to rh corner
10363  int VertSize = SelectRect.bottom - SelectRect.top;
10364  if((SelectRect.left + VertSize - Display->DisplayOffsetH) > Utilities->ScreenElementWidth)
10365  {
10366  // use right hand vertical & make square to left of that
10367  SelectRect.left = SelectRect.right - VertSize;
10368  }
10369  else
10370  {
10371  SelectRect.right = SelectRect.left + VertSize;
10372  }
10375  int button = Application->MessageBox
10376  (L"Original selection adjusted to make it square. 'OK' to keep this selection or 'Cancel' to make a new selection",
10377  L"Left click and hold here to move this message box", MB_OKCANCEL);
10378  if(button == IDCANCEL)
10379  {
10380  ResetSelectRect();
10381  Level1Mode = TrackMode; // call this first to clear everything, then set PrefDir mode
10382  SetLevel1Mode(134);
10384  SetLevel2TrackMode(61);
10386  Screen->Cursor = TCursor(-2); // Arrow
10387  Utilities->CallLogPop(2123);
10388  return;
10389  }
10390  }
10391  // set SelectBitmap (only need the dimensions here as not moving the selection)
10394  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
10395  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
10396 
10397  // store track elements and text in select vectors - have to store here because original selection might well have changed
10399  TTrackElement TempElement; // default element
10400  bool FoundFlag;
10401  for(int x = SelectRect.left; x < SelectRect.right; x++)
10402  {
10403  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
10404  {
10405  int ATVecPos = Track->GetVectorPositionFromTrackMap(58, x, y, FoundFlag);
10406  if(FoundFlag)
10407  {
10408  TempElement = Track->TrackElementAt(960, ATVecPos);
10409  if(TempElement.SpeedTag > 0)
10410  {
10411  Track->SelectPush(TempElement);
10412  }
10413  }
10414  }
10415  }
10416  // now store inactive elements
10417  for(int x = SelectRect.left; x < SelectRect.right; x++)
10418  {
10419  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
10420  {
10421  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(29, x, y, FoundFlag);
10422  if(FoundFlag)
10423  {
10424  TempElement = Track->InactiveTrackElementAt(128, IATVecPair.first);
10425  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
10426  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
10427  {
10428  TempElement = Track->InactiveTrackElementAt(129, IATVecPair.second);
10429  Track->SelectPush(TempElement);
10430  }
10431  }
10432  }
10433  }
10434  TrainController->LogEvent("RotLeft-trackstore ok");
10435  //store preferred directions //added at v2.9.0
10436  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
10437  TPrefDirElement TempPrefDirElement;
10439  for(int x = SelectRect.left; x < SelectRect.right; x++)
10440  {
10441  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
10442  {
10443  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(13, x, y, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
10444  if(FoundFlag)
10445  {
10446  if(PrefDirPos0 > -1)
10447  {
10448  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(10, PrefDirPos0);
10449  SelectPrefDir->ExternalStorePrefDirElement(16, TempPrefDirElement);
10450  }
10451  if(PrefDirPos1 > -1)
10452  {
10453  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(11, PrefDirPos1);
10454  SelectPrefDir->ExternalStorePrefDirElement(17, TempPrefDirElement);
10455  }
10456  if(PrefDirPos2 > -1)
10457  {
10458  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(12, PrefDirPos2);
10459  SelectPrefDir->ExternalStorePrefDirElement(18, TempPrefDirElement);
10460  }
10461  if(PrefDirPos3 > -1)
10462  {
10463  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(13, PrefDirPos3);
10464  SelectPrefDir->ExternalStorePrefDirElement(19, TempPrefDirElement);
10465  }
10466  }
10467  }
10468  }
10469  TrainController->LogEvent("RotLeft-PDstore ok");
10470  // store text items
10471  int LowSelectHPos = SelectRect.left * 16;
10472  int HighSelectHPos = SelectRect.right * 16;
10473  int LowSelectVPos = SelectRect.top * 16;
10474  int HighSelectVPos = SelectRect.bottom * 16;
10475  TextHandler->SelectTextVector.clear();
10476  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
10477  {
10478  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
10479  {
10480  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos < HighSelectVPos))
10481  {
10482  // have to create a new TextItem in order to create a new Font object
10483  // BUT: only create new items where they don't appear as named location names
10484  // in SelectVector, since those names shouldn't be copied or pasted.
10485  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
10486  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
10487  bool SelectVectorNamedElement = false;
10488  AnsiString SelectTextString; // new at v2.2.0
10489  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
10490  {
10491  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
10492  {
10493  SelectVectorNamedElement = true;
10494  break;
10495  }
10496  }
10497  if(SelectVectorNamedElement) // changed at v2.2.0
10498  {
10499  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
10500  }
10501  else // new at v2.2.0
10502  {
10503  SelectTextString = TextPtr->TextString;
10504  }
10505  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
10506  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
10507  }
10508  }
10509  }
10510  TrainController->LogEvent("RotLeft-textstore ok");
10511  // store graphic items, but first clear SelectGraphicVector
10512  Track->SelectGraphicVector.clear();
10513  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
10514  {
10515  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
10516  UserGraphicPtr++)
10517  {
10518  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) && (UserGraphicPtr->VPos >=
10519  LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
10520  {
10521  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
10522  }
10523  }
10524  }
10525  TrainController->LogEvent("RotLeft-graphicstore ok");
10526  // now transform the H & V for lh rotate
10527  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
10528  {
10529  int HLoc = SelectRect.left - SelectRect.top + Track->SelectVectorAt(76, x).VLoc;
10530  int VLoc = SelectRect.bottom - 1 + SelectRect.left - Track->SelectVectorAt(77, x).HLoc;
10532  TE.VLoc = VLoc;
10533  TE.HLoc = HLoc;
10534 
10535  TE.ActiveTrackElementName = Track->SelectVectorAt(66, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
10537  TE.Length01 = Track->SelectVectorAt(68, x).Length01;
10538  TE.Length23 = Track->SelectVectorAt(69, x).Length23;
10541  TE.SigAspect = Track->SelectVectorAt(72, x).SigAspect;
10542  Track->SelectVectorAt(73, x) = TE;
10543  }
10544 
10545  int RotLeftLinkArray[10] =
10546  {
10547  0, 7, 4, 1, 8, 5, 2, 9, 6, 3
10548  }; //0 & 5 are never used
10549  TrainController->LogEvent("RotLeft-trackrotate ok");
10550  // now transform the pref dirs
10551  for(unsigned int x = 0; x < SelectPrefDir->PrefDirSize(); x++)
10552  {
10553  int OriginalHLoc = SelectPrefDir->GetFixedPrefDirElementAt(255, x).HLoc; //added at v2.9.1
10554  int OriginalVLoc = SelectPrefDir->GetFixedPrefDirElementAt(256, x).VLoc;
10555  int HLoc = SelectRect.left - SelectRect.top + OriginalVLoc;
10556  int VLoc = SelectRect.bottom - 1 + SelectRect.left - OriginalHLoc;
10557  int ELink = RotLeftLinkArray[SelectPrefDir->GetFixedPrefDirElementAt(257, x).GetELink()];
10558  int XLink = RotLeftLinkArray[SelectPrefDir->GetFixedPrefDirElementAt(258, x).GetXLink()];
10560  //the above line caused errors when Track->GetTrackElementFromAnyTrackMap in RecoverClipboard had Vector passed in by value,
10561  //causing a bad returned value for SpeedTag and other properties. Passing it in by reference fixed it
10562  TPrefDirElement PDE(TE); //this has Link[4] set
10563  PDE.HLoc = HLoc;
10564  PDE.VLoc = VLoc;
10565  PDE.SetELink(ELink);
10566  PDE.SetXLink(XLink);
10567  bool ELinkPosFound = false, XLinkPosFound = false; //these ensure that the link pos is set as low as possible for points
10568  for(int y = 0; y < 4; y++) //changed to y at v2.9.1
10569  {
10570  if(!ELinkPosFound && (PDE.Link[y] == ELink))
10571  {
10572  PDE.SetELinkPos(y);
10573  ELinkPosFound = true;
10574  }
10575  if(!XLinkPosFound && (PDE.Link[y] == XLink))
10576  {
10577  PDE.SetXLinkPos(y);
10578  XLinkPosFound = true;
10579  }
10580  }
10581  //set the CheckCount as before - added at v2.9.1
10582  PDE.SetCheckCount(9); //explicitly set to 9 at v2.9.2
10585  //set the TrackVectorPosition to correspond to the corresponding TrackElement added at v2.9.1
10586  bool FoundFlag = false;
10587  PDE.SetTrackVectorPosition(Track->GetVectorPositionFromTrackMap(65, OriginalHLoc, OriginalVLoc, FoundFlag)); //uses original TV position as TrackMap hasn't changed yet
10588  if(PDE.GetSignedIntTrackVectorPosition() < 0)
10589  {
10590  FoundFlag = false; //probably will be anyway but reset to be sure & test below
10591  }
10593  if(!PDE.EntryExitNumber() || !ELinkPosFound || !XLinkPosFound || !FoundFlag) //error if can't set the number, any link pos not set or !FoundFlag
10594  {
10596  ShowMessage("Unable to re-orientate the preferred directions, these won't be set in the rotated selection");
10597  break;
10598  }
10599  SelectPrefDir->PrefDirVector.at(x) = PDE;
10600  }
10601  TrainController->LogEvent("RotLeft-PDrotate ok");
10602  // reset values in SelectTextVector
10603  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(4); x++)
10604  {
10605 // no point trying to locate text properly as it stays horizontal so will always be wrongly placed, just list all itels vertically at lhs
10606 // & if a lot then some will extend beyond the selection
10608  // also subtract half font height for each letter of text, brings position approximately right horizontally
10609  TextItem->HPos = (SelectRect.left) * 16;
10610  TextItem->VPos = (SelectRect.top + x) * 16;
10611  }
10612  TrainController->LogEvent("RotLeft-textrotate ok");
10613  // reset values in SelectGraphicVector
10614  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
10615  {
10616  int MidHPosBeforeRotate = Track->SelectGraphicVector.at(x).HPos + Track->SelectGraphicVector.at(x).Width / 2;
10617  int MidVPosBeforeRotate = Track->SelectGraphicVector.at(x).VPos + Track->SelectGraphicVector.at(x).Height / 2;
10618  int MidHPosAfterRotate = ((SelectRect.left - SelectRect.top) * 16) + MidVPosBeforeRotate;
10619  int MidVPosAfterRotate = ((SelectRect.bottom * 16) - 1) + (SelectRect.left * 16) - MidHPosBeforeRotate;
10620  int LeftPosAfterRotate = MidHPosAfterRotate - (Track->SelectGraphicVector.at(x).Width) / 2;
10621  int TopPosAfterRotate = MidVPosAfterRotate - (Track->SelectGraphicVector.at(x).Height) / 2;
10622  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterRotate;
10623  Track->SelectGraphicVector.at(x).VPos = TopPosAfterRotate;
10624  }
10625  Screen->Cursor = TCursor(-2); // Arrow
10627  SetLevel2TrackMode(62);
10628  Utilities->CallLogPop(2124);
10629  }
10630  catch(const Exception &e)
10631  {
10632  ErrorLog(206, e.Message);
10633  }
10634 }
10635 
10636 // ---------------------------------------------------------------------------
10637 
10638 void __fastcall TInterface::PasteMenuItemClick(TObject *Sender)
10639 {
10640  try
10641  {
10642  TrainController->LogEvent("PasteMenuItemClick");
10643  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PasteMenuItemClick");
10644  // Level1Mode = TrackMode;
10645  // SetLevel1Mode(74);
10647  SetLevel2TrackMode(58);
10648  Utilities->CallLogPop(2060);
10649  }
10650  catch(const Exception &e)
10651  {
10652  ErrorLog(198, e.Message);
10653  }
10654 }
10655 
10656 // ---------------------------------------------------------------------------
10657 void __fastcall TInterface::DeleteMenuItemClick(TObject *Sender)
10658 {
10659  try
10660  {
10661  TrainController->LogEvent("DeleteMenuItemClick");
10662  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteMenuItemClick");
10663  // Level1Mode = TrackMode;
10664  // SetLevel1Mode(75);
10666  SetLevel2TrackMode(38);
10667  Utilities->CallLogPop(1193);
10668  }
10669  catch(const Exception &e)
10670  {
10671  ErrorLog(153, e.Message);
10672  }
10673 }
10674 // ---------------------------------------------------------------------------
10675 
10676 void __fastcall TInterface::SelectLengthsMenuItemClick(TObject *Sender)
10677 {
10678  try
10679  {
10680  TrainController->LogEvent("SelectLengthsMenuItemClick");
10681  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectLengthsMenuItemClick");
10682  TrackElementPanel->Visible = false;
10683  TrackLengthPanel->Visible = true;
10684  TrackLengthPanel->SetFocus();
10685  SelectLengthsFlag = true;
10686  InfoPanel->Visible = true;
10687  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Set values or leave blank for no change";
10689  {
10690  ShowMessage("Note: length value will apply to each element's track within the selection.\n\nThis message will not be shown again.");
10691  LengthWarningSentFlag = true;
10692  }
10693  DistanceBox->Text = "";
10694  SpeedLimitBox->Text = "";
10697 // ResetChangedFileDataAndCaption(, true); //don't need this here after 2.7.0 as included in TrackLengthPanel buttons
10698  Utilities->CallLogPop(1414);
10699  }
10700  catch(const Exception &e)
10701  {
10702  ErrorLog(154, e.Message);
10703  }
10704 }
10705 
10706 // ---------------------------------------------------------------------------
10707 
10708 void __fastcall TInterface::SelectBiDirPrefDirsMenuItemClick(TObject *Sender)
10709 {
10710 /* SelectVector contains all the track elements (and inactive elements but don't need them), so create up to 4 PrefDir
10711  elements from each one, and add each into ConstructPrefDir, then when all added use ConsolidatePrefDirs to add to EveryPrefDir
10712 */
10713  try
10714  {
10715  TrainController->LogEvent("SelectBiDirPrefDirsMenuItemClick");
10716  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectBiDirPrefDirsMenuItemClick");
10718  bool FoundFlag = false;
10719  if(Track->SelectVector.empty())
10720  {
10721  Utilities->CallLogPop(1550);
10722  return;
10723  }
10724  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
10725  {
10726  TTrackElement TE = Track->SelectVectorAt(14, x);
10727  int VecPos = Track->GetVectorPositionFromTrackMap(42, TE.HLoc, TE.VLoc, FoundFlag);
10728  if(FoundFlag)
10729  {
10730  if((TE.TrackType == Points) || (TE.TrackType == Bridge) || (TE.TrackType == Crossover)) // 2-track element
10731  {
10732  TPrefDirElement PE0(TE, TE.Link[0], 0, TE.Link[1], 1, VecPos);
10734  TPrefDirElement PE1(TE, TE.Link[1], 1, TE.Link[0], 0, VecPos);
10736  TPrefDirElement PE2(TE, TE.Link[2], 2, TE.Link[3], 3, VecPos);
10738  TPrefDirElement PE3(TE, TE.Link[3], 3, TE.Link[2], 2, VecPos);
10740  }
10741  else if((TE.TrackType == Simple) || (TE.TrackType == Buffers) || (TE.TrackType == SignalPost) || (TE.TrackType == Continuation) ||
10742  (TE.TrackType == GapJump) || (TE.TrackType == FootCrossing))
10743  // need to list these explicitly since inactive elements will still be 'found' if there is an active element
10744  // at the same position
10745  {
10746  TPrefDirElement PE0(TE, TE.Link[0], 0, TE.Link[1], 1, VecPos);
10748  TPrefDirElement PE1(TE, TE.Link[1], 1, TE.Link[0], 0, VecPos);
10750  }
10751  }
10752  }
10754  ResetChangedFileDataAndCaption(22, false);
10755  // RlyFile = false; - don't alter this just for PrefDir changes
10756  Level1Mode = BaseMode; // call this first to clear everything, then set PrefDir mode
10757  SetLevel1Mode(30);
10759  SetLevel1Mode(31); // calls Clearand... to display all PrefDirs
10760  Utilities->CallLogPop(1549);
10761  }
10762  catch(const Exception &e)
10763  {
10764  ErrorLog(155, e.Message);
10765  }
10766 }
10767 
10768 // ---------------------------------------------------------------------------
10769 
10770 void __fastcall TInterface::CancelSelectionMenuItemClick(TObject *Sender)
10771 {
10772  try
10773  {
10774  TrainController->LogEvent("CancelSelectionClick");
10775  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CancelSelectionClick");
10776 // ClearandRebuildRailway(46); //called below
10777  SelectionValid = false;
10778  CancelSelectionFlag = true; // used to avoid RecoverClipboard in pasting when CutMoving selected
10779  Track->CopyFlag = false;
10781  if(Level1Mode == TrackMode)
10782  {
10783  SetLevel1Mode(76); // CancelSelectionFlag needed here
10785  SetLevel2TrackMode(68);
10786  }
10787  else if(Level1Mode == PrefDirMode)
10788  {
10789  SetLevel1Mode(32);
10790  }
10791  CancelSelectionFlag = false; // done with it
10792  ResetSelectRect();
10793  ClearandRebuildRailway(82); // to remove the selection outline
10794  Clipboard()->Clear();
10795  Clipboard()->Close();
10796  Utilities->CallLogPop(1413);
10797  }
10798  catch(const EClipboardException &e) //non-error catch - take no action
10799  {
10800 // Application->MessageBox(L"A clipboard error occurred in the cancel function", L"Message", MB_OK);
10801  TrainController->LogEvent("EClipboardException in CancelSelectionMenuItemClick - message = " + e.Message);
10802  Utilities->CallLogPop(2314);
10803  }
10804  catch(const Exception &e)
10805  {
10806  ErrorLog(156, e.Message);
10807  }
10808 }
10809 
10810 // ---------------------------------------------------------------------------
10811 
10812 void __fastcall TInterface::CheckPrefDirConflictsMenuItemClick(TObject *Sender)
10813 {
10814 //Conflicts consist of a preferred direction (PD) that links to a track element without a PD on it, or a PD that links to another PD that is set
10815 //in the wrong direction. Points or crossovers with no PD set on one leg are ok as a PD on the other leg doesn't link to it.
10816 
10817  try
10818  {
10819  TrainController->LogEvent("CheckPrefDirConflictsMenuItemClick");
10820  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CheckPrefDirConflictsMenuItemClick");
10821  bool FoundFlag; //not used
10822  int PD0, PD1, PD2, PD3, HLoc, VLoc, LastHLoc = -2000000, LastVLoc = -2000000; //well outside any conceivable range
10823  AnsiString TempInfo = InfoPanel->Caption;
10824  if(EveryPrefDir->PrefDirSize() <= 0)
10825  {
10826  ShowMessage("No preferred directions set.");
10827  Utilities->CallLogPop(2301);
10828  return;
10829  }
10830  else
10831  {
10832  //iterate the map rather than the vector so that pref dirs at the same H & V are consecutive, & can prevent the same element showing more than once
10833  InfoPanel->Visible = true;
10834  InfoPanel->Caption = "Checking preferred directions - please wait";
10835  InfoPanel->Update();
10836  THVPair LastHVPair;
10837  LastHVPair.first = -2000000;
10838  LastHVPair.second = -2000000; //well outside any conceivable range
10839  Screen->Cursor = TCursor(-11); // Hourglass
10840  for(TOnePrefDir::TPrefDir4MultiMapIterator PDMMIt = EveryPrefDir->PrefDir4MultiMap.begin(); PDMMIt != EveryPrefDir->PrefDir4MultiMap.end(); PDMMIt++)
10841  {
10842  bool BiDirLinkFound = true;
10843  int LinkedPrefDirVectorNumber; //not used
10844  THVPair CurrentHVPair = PDMMIt->first;
10845  if(CurrentHVPair != LastHVPair) //dont repeat for remaining elements at same position
10846  {
10847  //For bi-directional pref dirs as long as they link to another pref dir then ok, can't just link to a blank element
10848  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(16, PDMMIt->first.first, PDMMIt->first.second, FoundFlag, PD0, PD1, PD2, PD3);
10849  if((PD0 > -1) && (PD1 > -1))
10850  {
10851  if((EveryPrefDir->PrefDirVector.at(PD0).GetELink() == EveryPrefDir->PrefDirVector.at(PD1).GetXLink()) &&
10852  (EveryPrefDir->PrefDirVector.at(PD0).GetXLink() == EveryPrefDir->PrefDirVector.at(PD1).GetELink()))
10853  {
10854  //PD0 & PD1 are bidirectional pref dirs, ensure pref dirs link at both ends, direction doesn't matter for linked pref dir
10855  if(!EveryPrefDir->FindLinkingPrefDir(0, PD0, EveryPrefDir->PrefDirVector.at(PD0).GetELinkPos(),
10856  EveryPrefDir->PrefDirVector.at(PD0).GetELink(), LinkedPrefDirVectorNumber))
10857  {
10858  BiDirLinkFound = false;
10859  }
10860  if(!EveryPrefDir->FindLinkingPrefDir(1, PD0, EveryPrefDir->PrefDirVector.at(PD0).GetXLinkPos(),
10861  EveryPrefDir->PrefDirVector.at(PD0).GetXLink(), LinkedPrefDirVectorNumber))
10862  {
10863  BiDirLinkFound = false;
10864  }
10865  }
10866  }
10867  if(BiDirLinkFound && (PD0 > -1) && (PD2 > -1))
10868  {
10869  if((EveryPrefDir->PrefDirVector.at(PD0).GetELink() == EveryPrefDir->PrefDirVector.at(PD2).GetXLink()) &&
10870  (EveryPrefDir->PrefDirVector.at(PD0).GetXLink() == EveryPrefDir->PrefDirVector.at(PD2).GetELink()))
10871  {
10872  if(!EveryPrefDir->FindLinkingPrefDir(2, PD0, EveryPrefDir->PrefDirVector.at(PD0).GetELinkPos(),
10873  EveryPrefDir->PrefDirVector.at(PD0).GetELink(), LinkedPrefDirVectorNumber))
10874  {
10875  BiDirLinkFound = false;
10876  }
10877  if(!EveryPrefDir->FindLinkingPrefDir(3, PD0, EveryPrefDir->PrefDirVector.at(PD0).GetXLinkPos(),
10878  EveryPrefDir->PrefDirVector.at(PD0).GetXLink(), LinkedPrefDirVectorNumber))
10879  {
10880  BiDirLinkFound = false;
10881  }
10882  }
10883  }
10884  if(BiDirLinkFound && (PD0 > -1) && (PD3 > -1))
10885  {
10886  if((EveryPrefDir->PrefDirVector.at(PD0).GetELink() == EveryPrefDir->PrefDirVector.at(PD3).GetXLink()) &&
10887  (EveryPrefDir->PrefDirVector.at(PD0).GetXLink() == EveryPrefDir->PrefDirVector.at(PD3).GetELink()))
10888  {
10889  if(!EveryPrefDir->FindLinkingPrefDir(4, PD0, EveryPrefDir->PrefDirVector.at(PD0).GetELinkPos(),
10890  EveryPrefDir->PrefDirVector.at(PD0).GetELink(), LinkedPrefDirVectorNumber))
10891  {
10892  BiDirLinkFound = false;
10893  }
10894  if(!EveryPrefDir->FindLinkingPrefDir(5, PD0, EveryPrefDir->PrefDirVector.at(PD0).GetXLinkPos(),
10895  EveryPrefDir->PrefDirVector.at(PD0).GetXLink(), LinkedPrefDirVectorNumber))
10896  {
10897  BiDirLinkFound = false;
10898  }
10899  }
10900  }
10901  if(BiDirLinkFound && (PD1 > -1) && (PD2 > -1))
10902  {
10903  if((EveryPrefDir->PrefDirVector.at(PD1).GetELink() == EveryPrefDir->PrefDirVector.at(PD2).GetXLink()) &&
10904  (EveryPrefDir->PrefDirVector.at(PD1).GetXLink() == EveryPrefDir->PrefDirVector.at(PD2).GetELink()))
10905  {
10906  if(!EveryPrefDir->FindLinkingPrefDir(6, PD1, EveryPrefDir->PrefDirVector.at(PD1).GetELinkPos(),
10907  EveryPrefDir->PrefDirVector.at(PD1).GetELink(), LinkedPrefDirVectorNumber))
10908  {
10909  BiDirLinkFound = false;
10910  }
10911  if(!EveryPrefDir->FindLinkingPrefDir(7, PD1, EveryPrefDir->PrefDirVector.at(PD1).GetXLinkPos(),
10912  EveryPrefDir->PrefDirVector.at(PD1).GetXLink(), LinkedPrefDirVectorNumber))
10913  {
10914  BiDirLinkFound = false;
10915  }
10916  }
10917  }
10918  if(BiDirLinkFound && (PD1 > -1) && (PD3 > -1))
10919  {
10920  if((EveryPrefDir->PrefDirVector.at(PD1).GetELink() == EveryPrefDir->PrefDirVector.at(PD3).GetXLink()) &&
10921  (EveryPrefDir->PrefDirVector.at(PD1).GetXLink() == EveryPrefDir->PrefDirVector.at(PD3).GetELink()))
10922  {
10923  if(!EveryPrefDir->FindLinkingPrefDir(8, PD1, EveryPrefDir->PrefDirVector.at(PD1).GetELinkPos(),
10924  EveryPrefDir->PrefDirVector.at(PD1).GetELink(), LinkedPrefDirVectorNumber))
10925  {
10926  BiDirLinkFound = false;
10927  }
10928  if(!EveryPrefDir->FindLinkingPrefDir(9, PD1, EveryPrefDir->PrefDirVector.at(PD1).GetXLinkPos(),
10929  EveryPrefDir->PrefDirVector.at(PD1).GetXLink(), LinkedPrefDirVectorNumber))
10930  {
10931  BiDirLinkFound = false;
10932  }
10933  }
10934  }
10935  if(BiDirLinkFound && (PD2 > -1) && (PD3 > -1))
10936  {
10937  if((EveryPrefDir->PrefDirVector.at(PD2).GetELink() == EveryPrefDir->PrefDirVector.at(PD3).GetXLink()) &&
10938  (EveryPrefDir->PrefDirVector.at(PD2).GetXLink() == EveryPrefDir->PrefDirVector.at(PD3).GetELink()))
10939  {
10940  if(!EveryPrefDir->FindLinkingPrefDir(10, PD2, EveryPrefDir->PrefDirVector.at(PD2).GetELinkPos(),
10941  EveryPrefDir->PrefDirVector.at(PD2).GetELink(), LinkedPrefDirVectorNumber))
10942  {
10943  BiDirLinkFound = false;
10944  }
10945  if(!EveryPrefDir->FindLinkingPrefDir(11, PD2, EveryPrefDir->PrefDirVector.at(PD2).GetXLinkPos(),
10946  EveryPrefDir->PrefDirVector.at(PD2).GetXLink(), LinkedPrefDirVectorNumber))
10947  {
10948  BiDirLinkFound = false;
10949  }
10950  }
10951  }
10952  if(!BiDirLinkFound)
10953  {
10954  HLoc = EveryPrefDir->PrefDirVector.at(PDMMIt->second).HLoc;
10955  VLoc = EveryPrefDir->PrefDirVector.at(PDMMIt->second).VLoc;
10956  if((LastHLoc != HLoc) || (LastVLoc != VLoc))
10957  {
10958  LastHLoc = HLoc;
10959  LastVLoc = VLoc;
10960  while((Display->DisplayOffsetH - HLoc) > 0)
10961  {
10962  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
10963  }
10964  while((HLoc - Display->DisplayOffsetH) > (Utilities->ScreenElementWidth - 1))
10965  {
10967  }
10968  while((Display->DisplayOffsetV - VLoc) > 0)
10969  {
10970  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
10971  }
10972  while((VLoc - Display->DisplayOffsetV) > (Utilities->ScreenElementHeight - 1))
10973  {
10975  }
10977  Display->InvertElement(1, HLoc * 16, VLoc * 16);
10978  Screen->Cursor = TCursor(-2); // Arrow
10979  int Button = Application->MessageBox(L"Possible mismatch in preferred direction links \n"
10980  "at the position shown - see inverted element (may \n"
10981  "be behind this message). \n\n"
10982  "Click 'OK' to ignore and continue checking or \n"
10983  "'Cancel' to allow correction.", L"Warning", MB_OKCANCEL | MB_ICONWARNING);
10984  ClearandRebuildRailway(84); // to clear inversion
10985  if(Button == IDCANCEL)
10986  {
10987  InfoPanel->Caption = TempInfo;
10988  Utilities->CallLogPop(2302);
10989  return;
10990  }
10991  Screen->Cursor = TCursor(-11); // Hourglass
10992  Display->Update();
10993  }
10994  }
10995  }
10996  LastHVPair = CurrentHVPair;
10997 
10998  bool ELinkFound = false, BiDir = false;
10999  int ELink = EveryPrefDir->PrefDirVector.at(PDMMIt->second).GetELink();
11000  int ELinkPos = EveryPrefDir->PrefDirVector.at(PDMMIt->second).GetELinkPos();
11001  if(EveryPrefDir->BiDirectionalPrefDir(0, PDMMIt)) //bi-directional pref dirs dealt with above so don't check & don't mark as a conflict
11002  {
11003  BiDir = true;
11004  ELinkFound = true;
11005  }
11006  else if((ELink > -1) && (EveryPrefDir->PrefDirVector.at(PDMMIt->second).Conn[ELinkPos] > -1))
11007  {
11009  Track->TrackElementAt(1024, EveryPrefDir->PrefDirVector.at(PDMMIt->second).Conn[ELinkPos]).VLoc, FoundFlag, PD0, PD1, PD2, PD3);
11010  if((EveryPrefDir->PrefDirVector.at(PDMMIt->second).TrackType == GapJump) && (ELinkPos == 0)) //0 is the gap position
11011  {
11012  if(PD0 > -1)
11013  {
11014  if(EveryPrefDir->PrefDirVector.at(PD0).TrackType == GapJump) //the corresponding gap
11015  {
11016  if(EveryPrefDir->PrefDirVector.at(PD0).GetXLinkPos() == 0) // entry link is at the gap end so it corresponds
11017  {
11018  ELinkFound = true;
11019  }
11020  }
11021  }
11022  if(PD1 > -1)
11023  {
11024  if(EveryPrefDir->PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
11025  {
11026  if(EveryPrefDir->PrefDirVector.at(PD1).GetXLinkPos() == 0) // entry link is at the gap end so it corresponds
11027  {
11028  ELinkFound = true;
11029  }
11030  }
11031  }
11032  }
11033  if(PD0 > -1)
11034  {
11035  if(EveryPrefDir->PrefDirVector.at(PD0).GetXLink() == (10 - ELink))
11036  {
11037  ELinkFound = true;
11038  }
11039  }
11040  if(PD1 > -1)
11041  {
11042  if(EveryPrefDir->PrefDirVector.at(PD1).GetXLink() == (10 - ELink))
11043  {
11044  ELinkFound = true;
11045  }
11046  }
11047  if(PD2 > -1)
11048  {
11049  if(EveryPrefDir->PrefDirVector.at(PD2).GetXLink() == (10 - ELink))
11050  {
11051  ELinkFound = true;
11052  }
11053  }
11054  if(PD3 > -1)
11055  {
11056  if(EveryPrefDir->PrefDirVector.at(PD3).GetXLink() == (10 - ELink))
11057  {
11058  ELinkFound = true;
11059  }
11060  }
11061  }
11062  if(!ELinkFound && (BiDir || (EveryPrefDir->PrefDirVector.at(PDMMIt->second).Conn[ELinkPos] > -1)))
11063  {
11064  HLoc = EveryPrefDir->PrefDirVector.at(PDMMIt->second).HLoc;
11065  VLoc = EveryPrefDir->PrefDirVector.at(PDMMIt->second).VLoc;
11066  if((LastHLoc != HLoc) || (LastVLoc != VLoc))
11067  {
11068  LastHLoc = HLoc;
11069  LastVLoc = VLoc;
11070  while((Display->DisplayOffsetH - HLoc) > 0)
11071  {
11072  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
11073  }
11074  while((HLoc - Display->DisplayOffsetH) > (Utilities->ScreenElementWidth - 1))
11075  {
11077  }
11078  while((Display->DisplayOffsetV - VLoc) > 0)
11079  {
11080  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
11081  }
11082  while((VLoc - Display->DisplayOffsetV) > (Utilities->ScreenElementHeight - 1))
11083  {
11085  }
11087  Display->InvertElement(2, HLoc * 16, VLoc * 16);
11088  Screen->Cursor = TCursor(-2); // Arrow
11089  int Button = Application->MessageBox(L"Possible mismatch in preferred direction links \n"
11090  "at the position shown - see inverted element (may \n"
11091  "be behind this message). \n\n"
11092  "Click 'OK' to ignore and continue checking or \n"
11093  "'Cancel' to allow correction.", L"Warning", MB_OKCANCEL | MB_ICONWARNING);
11094  ClearandRebuildRailway(86); // to clear inversion
11095  if(Button == IDCANCEL)
11096  {
11097  InfoPanel->Caption = TempInfo;
11098  Utilities->CallLogPop(2303);
11099  return;
11100  }
11101  Screen->Cursor = TCursor(-11); //Hourglass
11102  Display->Update();
11103  }
11104  }
11105 
11106  bool XLinkFound = false;
11107  BiDir = false;
11108  int XLink = EveryPrefDir->PrefDirVector.at(PDMMIt->second).GetXLink();
11109  int XLinkPos = EveryPrefDir->PrefDirVector.at(PDMMIt->second).GetXLinkPos();
11110  if(EveryPrefDir->BiDirectionalPrefDir(1, PDMMIt)) //bi-directional pref dirs dealt with above so don't check & don't mark as a conflict
11111  {
11112  BiDir = true;
11113  XLinkFound = true;
11114  }
11115  else if((XLink > -1) && (EveryPrefDir->PrefDirVector.at(PDMMIt->second).Conn[XLinkPos] > -1))
11116  {
11118  Track->TrackElementAt(1026, EveryPrefDir->PrefDirVector.at(PDMMIt->second).Conn[XLinkPos]).VLoc, FoundFlag, PD0, PD1, PD2, PD3);
11119  if((EveryPrefDir->PrefDirVector.at(PDMMIt->second).TrackType == GapJump) && (XLinkPos == 0)) //0 is the gap position
11120  {
11121  if(PD0 > -1)
11122  {
11123  if(EveryPrefDir->PrefDirVector.at(PD0).TrackType == GapJump) //the corresponding gap
11124  {
11125  if(EveryPrefDir->PrefDirVector.at(PD0).GetELinkPos() == 0) // entry link is at the gap end so it corresponds
11126  {
11127  XLinkFound = true;
11128  }
11129  }
11130  }
11131  if(PD1 > -1)
11132  {
11133  if(EveryPrefDir->PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
11134  {
11135  if(EveryPrefDir->PrefDirVector.at(PD1).GetELinkPos() == 0) // entry link is at the gap end so it corresponds
11136  {
11137  XLinkFound = true;
11138  }
11139  }
11140  }
11141  }
11142  if(PD0 > -1)
11143  {
11144  if(EveryPrefDir->PrefDirVector.at(PD0).GetELink() == (10 - XLink))
11145  {
11146  XLinkFound = true;
11147  }
11148  }
11149  if(PD1 > -1)
11150  {
11151  if(EveryPrefDir->PrefDirVector.at(PD1).GetELink() == (10 - XLink))
11152  {
11153  XLinkFound = true;
11154  }
11155  }
11156  if(PD2 > -1)
11157  {
11158  if(EveryPrefDir->PrefDirVector.at(PD2).GetELink() == (10 - XLink))
11159  {
11160  XLinkFound = true;
11161  }
11162  }
11163  if(PD3 > -1)
11164  {
11165  if(EveryPrefDir->PrefDirVector.at(PD3).GetELink() == (10 - XLink))
11166  {
11167  XLinkFound = true;
11168  }
11169  }
11170  }
11171  if(!XLinkFound && (EveryPrefDir->PrefDirVector.at(PDMMIt->second).Conn[XLinkPos] > -1))
11172  {
11173  HLoc = EveryPrefDir->PrefDirVector.at(PDMMIt->second).HLoc;
11174  VLoc = EveryPrefDir->PrefDirVector.at(PDMMIt->second).VLoc;
11175  if((LastHLoc != HLoc) || (LastVLoc != VLoc))
11176  {
11177  LastHLoc = HLoc;
11178  LastVLoc = VLoc;
11179  while((Display->DisplayOffsetH - HLoc) > 0)
11180  {
11181  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
11182  }
11183  while((HLoc - Display->DisplayOffsetH) > (Utilities->ScreenElementWidth - 1))
11184  {
11186  }
11187  while((Display->DisplayOffsetV - VLoc) > 0)
11188  {
11189  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
11190  }
11191  while((VLoc - Display->DisplayOffsetV) > (Utilities->ScreenElementHeight - 1))
11192  {
11194  }
11196  Display->InvertElement(3, HLoc * 16, VLoc * 16);
11197  Screen->Cursor = TCursor(-2); // Arrow
11198  int Button = Application->MessageBox(L"Possible mismatch in preferred direction links \n"
11199  "at the position shown - see inverted element (may \n"
11200  "be behind this message). \n\n"
11201  "Click 'OK' to ignore and continue checking or \n"
11202  "'Cancel' to allow correction.", L"Warning", MB_OKCANCEL | MB_ICONWARNING);
11203  ClearandRebuildRailway(88); // to clear inversion
11204  if(Button == IDCANCEL)
11205  {
11206  InfoPanel->Caption = TempInfo;
11207  Utilities->CallLogPop(2304);
11208  return;
11209  }
11210  Screen->Cursor = TCursor(-11); // Hourglass
11211  Display->Update();
11212  }
11213  }
11214  }
11215  }
11216  Screen->Cursor = TCursor(-2); // Arrow
11217  ShowMessage("Finished");
11218  InfoPanel->Caption = TempInfo;
11219  Utilities->CallLogPop(2305);
11220  }
11221  catch(const Exception &e) //non-error catch
11222  {
11223  Screen->Cursor = TCursor(-2); // Arrow
11224  ShowMessage("Error in preferred direction checking, unable to complete the check");
11225  Utilities->CallLogPop(2306);
11226  }
11227 }
11228 
11229 //---------------------------------------------------------------------------
11230 
11231 void __fastcall TInterface::LoadTimetableMenuItemClick(TObject *Sender)
11232 {
11233  try
11234  {
11235  TrainController->LogEvent("LoadTimetableMenuItemClick");
11236  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LoadTimetableMenuItemClick");
11237  TimetableDialog->Filter = "Timetable file (*.ttb)|*.ttb";
11238  // reset all message flags, stops them being given twice new at v2.4.0
11239  TrainController->SSHigh = false;
11240  TrainController->MRSHigh = false;
11241  TrainController->MRSLow = false;
11242  TrainController->MassHigh = false;
11243  TrainController->BFHigh = false;
11244  TrainController->BFLow = false;
11245  TrainController->PwrHigh = false;
11246  TrainController->SigSHigh = false;
11247  TrainController->SigSLow = false;
11248  if(TimetableDialog->Execute())
11249  {
11250  if(TimetableDialog->InitialDir != TPath::GetDirectoryName(TimetableDialog->FileName)) // new at v2.6.0 to retain a new directory
11251  {
11252  TimetableDialog->InitialDir = TPath::GetDirectoryName(TimetableDialog->FileName);
11253  SaveTTDialog->InitialDir = TPath::GetDirectoryName(TimetableDialog->FileName);
11254  }
11255  TrainController->LogEvent("LoadTimetable " + TimetableDialog->FileName);
11256  bool CheckLocationsExistInRailwayTrue = true;
11257  if(TrainController->TimetableIntegrityCheck(0, AnsiString(TimetableDialog->FileName).c_str(), true, CheckLocationsExistInRailwayTrue))
11258  // true for GiveMessages
11259  {
11260  Screen->Cursor = TCursor(-11); // Hourglass;
11261  std::ifstream TTBLFile(AnsiString(TimetableDialog->FileName).c_str(), std::ios_base::binary);
11262  if(TTBLFile.is_open())
11263  {
11264  bool SessionFileFalse = false;
11265  if(BuildTrainDataVectorForLoadFile(0, TTBLFile, true, CheckLocationsExistInRailwayTrue, SessionFileFalse)) // true for GiveMessages
11266  {
11267  SaveTempTimetableFile(0, TimetableDialog->FileName);
11268  } // don't need an 'else' as messages given in BuildTrainDataVectorForLoadFile
11269 
11270  }
11271  else
11272  {
11273  ShowMessage("Failed to open timetable file, make sure it's spelled correctly, it exists and isn't open in another application");
11274  }
11275  Screen->Cursor = TCursor(-2); // Arrow
11276  } // if(TimetableIntegrityCheck
11277  else
11278  {
11279  ShowMessage("Timetable integrity check failed - unable to load " + TimetableDialog->FileName + ". Please check that the file exists and is spelled correctly.");
11280  }
11281  } // if(TimetableDialog->Execute())
11282 
11283  // else ShowMessage("Load Aborted");
11284  Utilities->CallLogPop(752);
11285  }
11286  catch(const Exception &e)
11287  {
11288  ErrorLog(34, e.Message);
11289  }
11290 }
11291 
11292 // ---------------------------------------------------------------------------
11293 void __fastcall TInterface::TakeSignallerControlMenuItemClick(TObject *Sender)
11294 {
11295  try
11296  {
11297  TrainController->LogEvent("SignallerControl1Click");
11298  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SignallerControl1Click");
11300  Train.SignallerStoppingFlag = false;
11301  Train.TrainMode = Signaller;
11302  if(Train.MaxRunningSpeed > Train.SignallerMaxSpeed)
11303  {
11304  Train.MaxRunningSpeed = Train.SignallerMaxSpeed;
11305  }
11306  if(Train.Stopped())
11307  {
11308  Train.SignallerStopped = true; // condition added at v2.4.0 to allow for taking sig control of failed moving trains
11309  }
11310  Train.CallingOnFlag = false; // in case was set, wouldn't start anyway if called on as SignallerStopped = true
11312  Train.PlotTrain(5, Display);
11313  AnsiString LocName = "";
11314  if(Train.LeadElement > -1)
11315  {
11316  LocName = Track->TrackElementAt(633, Train.LeadElement).ActiveTrackElementName;
11317  }
11318  if((LocName == "") && (Train.MidElement > -1))
11319  {
11320  LocName = Track->TrackElementAt(634, Train.MidElement).ActiveTrackElementName;
11321  }
11322  // store the value that allow restoration of tt control or not - RestoreTimetableLocation
11323  if(Train.StoppedAtLocation && (LocName != ""))
11324  {
11325  Train.RestoreTimetableLocation = LocName;
11326  }
11327  else
11328  {
11329  Train.RestoreTimetableLocation = "";
11330  }
11331  // check whether need to offer 'pass red signal'
11332  if(!Train.StoppedAtSignal && Train.StoppedAtLocation)
11333  {
11334  int NextElementPosition = Track->TrackElementAt(775, Train.LeadElement).Conn[Train.LeadExitPos];
11335  int NextEntryPos = Track->TrackElementAt(776, Train.LeadElement).ConnLinkPos[Train.LeadExitPos];
11336  if((NextElementPosition > -1) && (NextEntryPos > -1))
11337  {
11338  if((Track->TrackElementAt(777, NextElementPosition).Config[Track->GetNonPointsOppositeLinkPos(NextEntryPos)] == Signal) &&
11339  (Track->TrackElementAt(778, NextElementPosition).Attribute == 0))
11340  {
11341  // set both StoppedAtLocation & StoppedAtSignal, so that 'pass red signal' is offered in popup menu rather than move
11342  // forwards, but don't change the background colour so still shows as stopped at location
11343  Train.StoppedAtSignal = true;
11344  }
11345  }
11346  }
11347  // find element ID if no locname
11348  if((LocName == "") && Train.LeadElement > -1)
11349  {
11350  LocName = Track->TrackElementAt(635, Train.LeadElement).ElementID;
11351  }
11352  if((LocName == "") && (Train.MidElement > -1))
11353  {
11354  LocName = Track->TrackElementAt(636, Train.MidElement).ElementID;
11355  }
11356  Train.LogAction(0, Train.HeadCode, "", TakeSignallerControl, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
11357  Utilities->CallLogPop(1772);
11358  }
11359  catch(const Exception &e)
11360  {
11361  ErrorLog(157, e.Message);
11362  }
11363 }
11364 
11365 // ---------------------------------------------------------------------------
11366 
11367 void __fastcall TInterface::TimetableControlMenuItemClick(TObject *Sender)
11368 {
11369  try
11370  {
11371  TrainController->LogEvent("TimetableControlMenuItemClick");
11372  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TimetableControlMenuItemClick");
11374  Train.SignallerStoppingFlag = false;
11375  Train.TrainMode = Timetable;
11376  Train.SignallerStopped = false;
11377  Train.StoppedAfterSPAD = false;
11378  Train.SPADFlag = false;
11381 // red headcode[0]
11382  Train.PlotTrain(6, Display);
11383  AnsiString LocName = "", LeadElementLocName = "", MidElementLocName = "", RequiredLocName = Train.ActionVectorEntryPtr->LocationName;
11384  if(Train.LeadElement > -1) //this naming procedure changed at v2.9.1 as a train might have one element at a station and the other at a non-station named location
11385  //but only one is the location in the timetable, and that is the RequiredLocName. Discovered for LS41 at Lincoln.
11386  {
11387  LeadElementLocName = Track->TrackElementAt(645, Train.LeadElement).ActiveTrackElementName;
11388  }
11389  if(Train.MidElement > -1)
11390  {
11391  MidElementLocName = Track->TrackElementAt(647, Train.MidElement).ActiveTrackElementName;
11392  }
11393  if((LeadElementLocName == "") && (MidElementLocName == "") && (Train.LeadElement > -1))
11394  {
11395  LeadElementLocName = Track->TrackElementAt(646, Train.LeadElement).ElementID;
11396  }
11397  if((LeadElementLocName == "") && (Train.MidElement > -1))
11398  {
11399  MidElementLocName = Track->TrackElementAt(648, Train.MidElement).ElementID;
11400  }
11401  if((LeadElementLocName == RequiredLocName) || (MidElementLocName == RequiredLocName))
11402  {
11403  LocName = RequiredLocName;
11404  }
11405  if((Train.ActionVectorEntryPtr->LocationType == AtLocation) && (LocName == Train.ActionVectorEntryPtr->LocationName))
11406  {
11407  Train.StoppedAtLocation = true;
11408  Train.StoppedAtSignal = false;
11409 // added at v2.7.0 as if had been stopped at signal before tt control restored then background colour would change to normal when signal cleared even when not due to depart
11410  Train.LastActionTime = TrainController->TTClockTime; // by itself this only affects trains that have still to arrive, if waiting to
11411  // depart the departure time & TRS time have already been calculated so need to
11412  // force a recalculation - see below
11413  Train.DepartureTimeSet = false; // force it to be recalculated based on new LastActionTime (if waiting to arrive this is false anyway)
11414  if(!Train.TrainFailed)
11415  {
11417  } // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11418 
11419  if((Train.ActionVectorEntryPtr->FormatType == TimeLoc) && (Train.ActionVectorEntryPtr->ArrivalTime >= TDateTime(0)))
11420  {
11421  // Timetable indicates that train still waiting to arrive for a TimeLoc arrival so send message and mark as arrived
11422  Train.LogAction(28, Train.HeadCode, "", Arrive, LocName, Train.ActionVectorEntryPtr->ArrivalTime, Train.ActionVectorEntryPtr->Warning);
11423  Train.ActionVectorEntryPtr++; // advance pointer past arrival //added at v1.2.0
11424  }
11425  else if((Train.ActionVectorEntryPtr->FormatType == TimeTimeLoc) && !(Train.TimeTimeLocArrived))
11426  {
11427  // Timetable indicates that train still waiting to arrive for a TimeTimeLoc arrival so send message and mark as arrived
11428  Train.LogAction(29, Train.HeadCode, "", Arrive, LocName, Train.ActionVectorEntryPtr->ArrivalTime, Train.ActionVectorEntryPtr->Warning);
11429  Train.TimeTimeLocArrived = true;
11430  // NB: No need for 'Train.ActionVectorEntryPtr++' because still to act on the departure time
11431  }
11432  }
11433  else
11434  {
11435  int NextElementPos = -1; // addition for v1.3.2 due to Carwyn Thomas' error
11436  int NextEntryPos = -1; // ---ditto---
11437  if(Train.LeadElement > -1) // ---ditto---
11438  {
11439  // ---ditto---
11440  NextElementPos = Track->TrackElementAt(658, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
11441  NextEntryPos = Track->TrackElementAt(659, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
11442  } // ---ditto---
11443 
11444  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11445  if(!Train.TrainFailed)
11446  {
11447  Train.PlotTrainWithNewBackgroundColour(31, clNormalBackground, Display); // to remove other background if was present, moved from
11448  } // within Train.AbleToMove at v2.4.0 to cancel signal stop background
11449 
11450  if(Train.AbleToMove(1)) // if has no power
11451  {
11452  Train.EntrySpeed = 0; // moved from below for v1.3.2 after Carwyn Thomas error
11453  Train.EntryTime = TrainController->TTClockTime; // ---Ditto---
11454  Train.FirstHalfMove = true; // ---Ditto---
11455  if((NextElementPos > -1) && (NextEntryPos > -1)) // changed from if(NextElementPos >= 0) as above
11456  {
11457  // Train.EntrySpeed = 0;
11458  // Train.EntryTime = TrainController->TTClockTime;
11459  // Train.FirstHalfMove = true;
11460  Train.SetTrainMovementValues(15, NextElementPos, NextEntryPos);
11461  }
11462  // else follow the continuations //added these 3 conditions for v1.3.2 after Carwyn Thomas error
11463  else if((Train.LeadElement > -1) && (Track->TrackElementAt(894, Train.LeadElement).TrackType == Continuation))
11464  {
11465  Train.SetTrainMovementValues(21, Train.LeadElement, Train.LeadEntryPos); // Use LeadElement for calcs if lead is a continuation
11466  }
11467  else if((Train.MidElement > -1) && (Track->TrackElementAt(895, Train.MidElement).TrackType == Continuation))
11468  {
11469  Train.SetTrainMovementValues(22, Train.MidElement, Train.MidEntryPos); // Use MidElement for calcs if Mid is a continuation
11470  }
11471  else if((Train.LagElement > -1) && (Track->TrackElementAt(896, Train.LagElement).TrackType == Continuation))
11472  {
11473  Train.SetTrainMovementValues(23, Train.LagElement, Train.LagEntryPos); // Use LagElement for calcs if Lag is a continuation
11474  }
11475  }
11476  else if(Train.StoppedAtSignal)
11477  {
11478  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11479  if(!Train.TrainFailed)
11480  {
11482  }
11483  // TrainController->LogActionError(42, Train.HeadCode, "", SignalHold, Track->TrackElementAt(757, NextElementPos).ElementID);
11484  }
11485  }
11486  Train.LogAction(1, Train.HeadCode, "", RestoreTimetableControl, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
11487  Utilities->CallLogPop(1195);
11488  }
11489  catch(const Exception &e)
11490  {
11491  ErrorLog(158, e.Message);
11492  }
11493 }
11494 
11495 // ---------------------------------------------------------------------------
11496 
11497 void __fastcall TInterface::ChangeDirectionMenuItemClick(TObject *Sender)
11498 {
11499  try
11500  {
11501  TrainController->LogEvent("ChangeDirectionMenuItemClick");
11502  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ChangeDirectionMenuItemClick");
11504  Train.SignallerStoppingFlag = false;
11505  Train.SignallerChangeTrainDirection(0); // this unplots & replots train, which checks for facing signal and sets StoppedAtSignal if req'd
11506  Train.SignallerStopped = true;
11507  AnsiString LocName = "";
11508  if(Train.LeadElement > -1)
11509  {
11510  LocName = Track->TrackElementAt(637, Train.LeadElement).ActiveTrackElementName;
11511  }
11512  if((LocName == "") && (Train.MidElement > -1))
11513  {
11514  LocName = Track->TrackElementAt(638, Train.MidElement).ActiveTrackElementName;
11515  }
11516  if((LocName == "") && Train.LeadElement > -1)
11517  {
11518  LocName = Track->TrackElementAt(639, Train.LeadElement).ElementID;
11519  }
11520  if((LocName == "") && (Train.MidElement > -1))
11521  {
11522  LocName = Track->TrackElementAt(640, Train.MidElement).ElementID;
11523  }
11524  Train.LogAction(2, Train.HeadCode, "", SignallerChangeDirection, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
11525  Utilities->CallLogPop(1196);
11526  }
11527  catch(const Exception &e)
11528  {
11529  ErrorLog(159, e.Message);
11530  }
11531 }
11532 // ---------------------------------------------------------------------------
11533 
11534 void __fastcall TInterface::MoveForwardsMenuItemClick(TObject *Sender)
11535 {
11536  try
11537  {
11538  TrainController->LogEvent("MoveForwardsMenuItemClick");
11539  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveForwardsMenuItemClick");
11541  Train.SignallerStoppingFlag = false;
11542  if(!Train.AbleToMove(2))
11543  {
11544  // shouldn't be here as when unable to move MoveForwards shouldn't be enabled, but leave in as a precaution
11545  Utilities->CallLogPop(1197);
11546  return;
11547  }
11548  Train.SignallerStopped = false;
11549  Train.StoppedAfterSPAD = false; // in case had been set
11550  Train.SPADFlag = false;
11551  Train.StoppedAtLocation = false; // may not have been set but reset anyway
11552  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11554  Train.EntrySpeed = 0;
11556  Train.FirstHalfMove = true;
11557  int NextElementPos = -1; // addition for v1.3.2 due to Carwyn Thomas error
11558  int NextEntryPos = -1; // ---ditto---
11559  if(Train.LeadElement > -1) // ---ditto---
11560  {
11561  // ---ditto---
11562  NextElementPos = Track->TrackElementAt(652, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
11563  NextEntryPos = Track->TrackElementAt(657, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
11564  } // ---ditto---
11565 
11566  if((NextElementPos > -1) && (NextEntryPos > -1))
11567  {
11568  Train.SetTrainMovementValues(14, NextElementPos, NextEntryPos); // NextElement is the element to be entered
11569  }
11570  // else follow the continuations
11571  else if((Train.LeadElement > -1) && (Track->TrackElementAt(784, Train.LeadElement).TrackType == Continuation))
11572  {
11573  Train.SetTrainMovementValues(17, Train.LeadElement, Train.LeadEntryPos); // Use LeadElement for calcs if lead is a continuation
11574  }
11575  else if((Train.MidElement > -1) && (Track->TrackElementAt(785, Train.MidElement).TrackType == Continuation))
11576  {
11577  Train.SetTrainMovementValues(18, Train.MidElement, Train.MidEntryPos); // Use MidElement for calcs if Mid is a continuation
11578  }
11579  else if((Train.LagElement > -1) && (Track->TrackElementAt(786, Train.LagElement).TrackType == Continuation))
11580  {
11581  Train.SetTrainMovementValues(19, Train.LagElement, Train.LagEntryPos); // Use LagElement for calcs if Lag is a continuation
11582  }
11583  Train.LogAction(3, Train.HeadCode, "", SignallerMoveForwards, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
11584  Utilities->CallLogPop(1198);
11585  }
11586  catch(const Exception &e)
11587  {
11588  ErrorLog(160, e.Message);
11589  }
11590 }
11591 // ---------------------------------------------------------------------------
11592 
11593 void __fastcall TInterface::SignallerJoinedByMenuItemClick(TObject *Sender)
11594 {
11595  // new at v2.4.0
11596  try
11597  {
11598  TrainController->LogEvent("JoinedByMenuItemClick");
11599  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",JoinedByMenuItemClick");
11600  TTrain *TrainToBeJoinedBy;
11602  if(ThisTrain.IsThereAnAdjacentTrain(1, TrainToBeJoinedBy)) // this must come before both powers zero check in order to set a valid TrainToBeJoinedBy
11603  {
11604  if(TrainToBeJoinedBy->TrainMode != Signaller)
11605  {
11606  TrainController->StopTTClockMessage(91, "Adjacent train must be under signaller control in order to join");
11607  Utilities->CallLogPop(2156);
11608  return;
11609  }
11610  // here if there is an adjacent train under signaller control
11611  if((TrainToBeJoinedBy->PowerAtRail < 1) && (ThisTrain.PowerAtRail < 1))
11612  {
11613  ShowMessage("Can't join two trains when both are without power");
11614  Utilities->CallLogPop(2157);
11615  return;
11616  }
11617  AnsiString TrainToBeJoinedByHeadCode = TrainToBeJoinedBy->HeadCode;
11618  // set new values for mass etc
11619  double OtherBrakeForce = TrainToBeJoinedBy->MaxBrakeRate * TrainToBeJoinedBy->Mass;
11620  double OwnBrakeForce = ThisTrain.MaxBrakeRate * ThisTrain.Mass;
11621  double CombinedBrakeRate = (OtherBrakeForce + OwnBrakeForce) / (TrainToBeJoinedBy->Mass + ThisTrain.Mass);
11622  ThisTrain.Mass += TrainToBeJoinedBy->Mass;
11623  ThisTrain.MaxBrakeRate = CombinedBrakeRate;
11624  ThisTrain.PowerAtRail += TrainToBeJoinedBy->PowerAtRail;
11625  ThisTrain.AValue = sqrt(2 * ThisTrain.PowerAtRail / ThisTrain.Mass);
11626 
11627  TrainToBeJoinedBy->TrainGone = true; // this will cause other train to be deleted
11628  TrainToBeJoinedBy->JoinedOtherTrainFlag = true;
11629  AnsiString LocName = "";
11630  if(ThisTrain.LeadElement > -1)
11631  {
11632  LocName = Track->TrackElementAt(979, ThisTrain.LeadElement).ActiveTrackElementName;
11633  }
11634  if((LocName == "") && (ThisTrain.MidElement > -1))
11635  {
11636  LocName = Track->TrackElementAt(980, ThisTrain.MidElement).ActiveTrackElementName;
11637  }
11638  if((LocName == "") && ThisTrain.LeadElement > -1)
11639  {
11640  LocName = Track->TrackElementAt(981, ThisTrain.LeadElement).ElementID;
11641  }
11642  if((LocName == "") && (ThisTrain.MidElement > -1))
11643  {
11644  LocName = Track->TrackElementAt(982, ThisTrain.MidElement).ElementID;
11645  }
11646  ThisTrain.StoppedWithoutPower = true;
11647  if(ThisTrain.PowerAtRail >= 1)
11648  {
11649  ThisTrain.StoppedWithoutPower = false;
11650  }
11651  ThisTrain.TrainFailed = false; // if had failed then no longer failed, even if joining train has no power
11652  if(!ThisTrain.StoppedAtLocation)
11653  {
11654  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11656  }
11657  else
11658  {
11659  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11661  }
11662  ThisTrain.SignallerStopped = true; // maybe as well as stopped without power, thought that takes precedence in floating window
11663  ThisTrain.LogAction(34, ThisTrain.HeadCode, TrainToBeJoinedBy->HeadCode, SignallerJoin, LocName, TDateTime(0), false); // TDateTime isn't used
11664  ThisTrain.ZeroPowerNoFrontSplitMessage = false; // added at v2.4.0, no need to include TrainToBeJoinedBy as that will be removed
11665  ThisTrain.ZeroPowerNoRearSplitMessage = false;
11666  ThisTrain.FailedTrainNoFinishJoinMessage = false;
11667  ThisTrain.ZeroPowerNoJoinedByMessage = false;
11668  ThisTrain.ZeroPowerNoCDTMessage = false;
11669  ThisTrain.ZeroPowerNoNewServiceMessage = false;
11671  ThisTrain.ZeroPowerNoRepeatShuttleMessage = false;
11673  Utilities->CallLogPop(2158);
11674  }
11675  }
11676  catch(const Exception &e)
11677  {
11678  ErrorLog(207, e.Message);
11679  }
11680 }
11681 // ---------------------------------------------------------------------------
11682 
11683 void __fastcall TInterface::RepairFailedTrainMenuItemClick(TObject *Sender)
11684 {
11685  // added at v2.4.0
11686  try
11687  {
11688  TrainController->LogEvent("RepairFailedTrainMenuItemClick");
11689  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedTrainMenuItemClick");
11691  Train.TrainFailed = false;
11692  Train.StoppedWithoutPower = false;
11693  Train.SignallerStopped = true;
11694  if(!Train.StoppedAtLocation)
11695  {
11696  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11698  }
11699  else
11700  {
11701  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11703  }
11704  Train.PowerAtRail = Train.OriginalPowerAtRail; // recover from original value, new at v2.4.0
11705  Train.AValue = sqrt(2 * Train.PowerAtRail / Train.Mass);
11706  Train.SetTrainMovementValues(24, Train.LeadElement, Train.LeadEntryPos);
11707  AnsiString LocName = "";
11708  if(Train.LeadElement > -1)
11709  {
11710  LocName = Track->TrackElementAt(983, Train.LeadElement).ActiveTrackElementName;
11711  }
11712  if((LocName == "") && (Train.MidElement > -1))
11713  {
11714  LocName = Track->TrackElementAt(984, Train.MidElement).ActiveTrackElementName;
11715  }
11716  if((LocName == "") && Train.LeadElement > -1)
11717  {
11718  LocName = Track->TrackElementAt(985, Train.LeadElement).ElementID;
11719  }
11720  if((LocName == "") && (Train.MidElement > -1))
11721  {
11722  LocName = Track->TrackElementAt(986, Train.MidElement).ElementID;
11723  }
11724  Train.LogAction(35, Train.HeadCode, "", RepairFailedTrain, LocName, TrainController->TTClockTime, false); // false for no warning
11725  Train.ZeroPowerNoFrontSplitMessage = false;
11726  Train.ZeroPowerNoRearSplitMessage = false;
11727  Train.FailedTrainNoFinishJoinMessage = false;
11728  Train.ZeroPowerNoJoinedByMessage = false;
11729  Train.ZeroPowerNoCDTMessage = false;
11730  Train.ZeroPowerNoNewServiceMessage = false;
11732  Train.ZeroPowerNoRepeatShuttleMessage = false;
11734  Utilities->CallLogPop(2159);
11735  }
11736  catch(const Exception &e)
11737  {
11738  ErrorLog(208, e.Message);
11739  }
11740 }
11741 
11742 // ---------------------------------------------------------------------------
11743 
11744 void __fastcall TInterface::SignallerControlStopMenuItemClick(TObject *Sender)
11745 {
11746  try
11747  {
11748  TrainController->LogEvent("SignallerControlStopMenuItemClick");
11749  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SignallerControlStopMenuItemClick");
11752  if(Train.LeadElement > -1)
11753  {
11754  if(Track->TrackElementAt(787, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
11755  {
11756  Train.SignallerStoppingFlag = true;
11757  Train.SignallerStopBrakeRate = 0;
11758  Train.LogAction(24, Train.HeadCode, "", SignallerControlStop, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
11759  }
11760  else
11761  {
11763  }
11764  }
11765  else
11766  {
11768  }
11769  Utilities->CallLogPop(1553);
11770  }
11771  catch(const Exception &e)
11772  {
11773  ErrorLog(161, e.Message);
11774  }
11775 }
11776 
11777 // ---------------------------------------------------------------------------
11778 void __fastcall TInterface::PassRedSignalMenuItemClick(TObject *Sender)
11779 {
11780  try
11781  {
11782  TrainController->LogEvent("PassRedSignalMenuItemClick");
11783  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PassRedSignalMenuItemClick");
11785  Train.SignallerStoppingFlag = false;
11786  int NextElementPos = Track->TrackElementAt(712, Train.LeadElement).Conn[Train.LeadExitPos];
11787  if(NextElementPos < 0)
11788  {
11789  throw Exception("Error, no element in front in PassRedSignalMenuItemClick");
11790  }
11791  TTrackElement &TrackElement = Track->TrackElementAt(653, NextElementPos);
11792 /* drop this error as may be some circumstances where behind a signal in sig mode but not stopped at signal
11793  if(!Train.StoppedAtSignal)
11794  {
11795  throw Exception("Error, not StoppedAtSignal in PassRedSignalMenuItemClick");
11796  }
11797 */
11798  if(TrackElement.TrackType != SignalPost)
11799  {
11800  throw Exception("Error, next element not a signal type in PassRedSignalMenuItemClick");
11801  }
11802  Train.SignallerStopped = false;
11803  Train.StoppedAtLocation = false; // may have started at station in signaller mode and also at a red signal, in this case both SignallerStopped
11804  // and StoppedAtLocation are set but the background colour stays pale green for station, not signal,
11805  // since no need to alert the user
11806  Train.StoppedAfterSPAD = false; // in case had been set
11807  Train.SPADFlag = false;
11808  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11810  Train.AllowedToPassRedSignal = true;
11811  Train.LogAction(4, Train.HeadCode, "", SignallerPassRedSignal, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
11812  Utilities->CallLogPop(1199);
11813  }
11814  catch(const Exception &e)
11815  {
11816  ErrorLog(162, e.Message);
11817  }
11818 }
11819 // ---------------------------------------------------------------------------
11820 
11821 void __fastcall TInterface::StepForwardMenuItemClick(TObject *Sender)
11822 {
11823  try
11824  {
11825  TrainController->LogEvent("StepForwardMenuItemClick");
11826  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",StepForwardMenuItemClick");
11828  Train.SignallerStoppingFlag = false;
11829  Train.SignallerStopped = false;
11830  Train.StoppedAtLocation = false; // may have started at station in signaller mode and also at a red signal, in this case both SignallerStopped
11831  // and StoppedAtLocation are set but the background colour stays pale green for station, not signal,
11832  // since no need to alert the user
11833  Train.StoppedAfterSPAD = false; // in case had been set
11834  Train.SPADFlag = false;
11835  Train.StepForwardFlag = true;
11836  Train.AllowedToPassRedSignal = true; // in case at a signal, will clear when half-way into next element whether a signal or not
11837  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11839  Train.LogAction(32, Train.HeadCode, "", SignallerStepForward, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
11840  int NextElementPos = -1;
11841 // addition for v1.3.2 due to Carwyn Thomas error: can't select StepForwardMenuItem if exiting at a continuation but leave this in anyway
11842  int NextEntryPos = -1; // ---ditto---
11843  if(Train.LeadElement > -1) // ---ditto---
11844  {
11845  // ---ditto---
11846  NextElementPos = Track->TrackElementAt(804, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
11847  NextEntryPos = Track->TrackElementAt(805, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
11848  } // ---ditto---
11849 
11850  if((NextElementPos > -1) && (NextEntryPos > -1))
11851  {
11852  // call this after StepForwardFlag set
11853  Train.EntrySpeed = 0;
11855  Train.FirstHalfMove = true;
11856  Train.SetTrainMovementValues(20, NextElementPos, NextEntryPos); // NextElement is the element to be entered
11857  }
11858  Utilities->CallLogPop(1800);
11859  }
11860  catch(const Exception &e)
11861  {
11862  ErrorLog(163, e.Message);
11863  }
11864 }
11865 
11866 // ---------------------------------------------------------------------------
11867 
11868 void __fastcall TInterface::RemoveTrainMenuItemClick(TObject *Sender)
11869 {
11870  try
11871  {
11872  TrainController->LogEvent("RemoveTrainMenuItemClick");
11873  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RemoveTrainMenuItemClick");
11875  if((!Train.Derailed) && (!Train.Crashed))
11876  {
11877  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
11879  UnicodeString Message = UnicodeString(Train.HeadCode) + " will be removed from the railway - proceed?";
11880  int button = Application->MessageBox(Message.c_str(), L"Please confirm", MB_YESNO);
11881  TrainController->BaseTime = TDateTime::CurrentDateTime();
11883  if(button == IDNO)
11884  {
11885  Utilities->CallLogPop(1801);
11886  return;
11887  }
11888  }
11889  Train.SignallerStoppingFlag = false;
11890  Train.TrainGone = true; // will be removed by TTrainController::Operate
11891  Train.SignallerRemoved = true;
11892  Train.TrainDataEntryPtr->TrainOperatingDataVector.at(Train.RepeatNumber).RunningEntry = Exited;
11893  AnsiString LocName = "";
11894  if(Train.LeadElement > -1)
11895  {
11896  LocName = Track->TrackElementAt(641, Train.LeadElement).ActiveTrackElementName;
11897  }
11898  if((LocName == "") && (Train.MidElement > -1))
11899  {
11900  LocName = Track->TrackElementAt(642, Train.MidElement).ActiveTrackElementName;
11901  }
11902  if((LocName == "") && Train.LeadElement > -1)
11903  {
11904  LocName = Track->TrackElementAt(643, Train.LeadElement).ElementID;
11905  }
11906  if((LocName == "") && (Train.MidElement > -1))
11907  {
11908  LocName = Track->TrackElementAt(644, Train.MidElement).ElementID;
11909  }
11910  TTrackElement *TrackElementPtr;
11911  int RouteNumber;
11912  TAllRoutes::TRouteType RouteType;
11913  if(Train.LeadElement > -1)
11914  {
11915  TrackElementPtr = &(Track->TrackElementAt(673, Train.LeadElement));
11916  // remove TrainIDs from track element, added at v2.4.0
11917  if(TrackElementPtr->TrackType == Bridge)
11918  {
11919  if(Train.LeadExitPos > 1)
11920  {
11921  TrackElementPtr->TrainIDOnBridgeTrackPos23 = -1;
11922  }
11923  else
11924  {
11925  TrackElementPtr->TrainIDOnBridgeTrackPos01 = -1;
11926  }
11927  }
11928  else
11929  {
11930  TrackElementPtr->TrainIDOnElement = -1;
11931  }
11932  // reset any CallingOnSet flags for signals, if facing wrong way doesn't matter, shouldn't be set anyay
11933  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
11934  {
11935  TrackElementPtr->CallingOnSet = false;
11936  Track->PlotSignal(6, *TrackElementPtr, Display);
11937  }
11938 // [added at v1.3.0] here check if on an automatic signals route and if so reset signals for the entire route from the
11939 // start of the route - after the train has been removed, use LeadElement and also MidElement (if no autosigs route at LeadElement) just to be sure
11940  RouteType = AllRoutes->GetRouteTypeAndNumber(27, Train.LeadElement, Train.LeadEntryPos, RouteNumber);
11941  if(RouteType == TAllRoutes::AutoSigsRoute)
11942  {
11945  }
11946 // end of addition
11947 
11948 // erase a stub route if there is one, added at v2.6.1
11949 // first element of route is immediately in front of the train
11950  if(Train.LeadExitPos >= 0)
11951  {
11952  TTrackElement LeadTrackElement = Track->TrackElementAt(1013, Train.LeadElement);
11953  int FirstRouteElementVecPos = LeadTrackElement.Conn[Train.LeadExitPos];
11954  int FirstRouteLinkPos = LeadTrackElement.ConnLinkPos[Train.LeadExitPos];
11955  RouteType = AllRoutes->GetRouteTypeAndNumber(39, FirstRouteElementVecPos, FirstRouteLinkPos, RouteNumber);
11956  if(RouteType == TAllRoutes::NotAutoSigsRoute) // red or green route, if no route then ignore
11957  {
11958  TOneRoute &OR = AllRoutes->GetModifiableRouteAt(30, RouteNumber);
11959  TTrackElement TE = Track->TrackElementAt(1014, FirstRouteElementVecPos);
11960  if((TE.TrackType != SignalPost) && (TE.TrackType != Continuation))
11961  // all autosigs routes have signalpost or continuation at 0 so they are automatically excluded
11962  {
11963  bool FirstPass = true; //added at v2.8.0
11964  while(OR.PrefDirSize() > 0)
11965  // remove the route up to but not including the next facing signal, in case a route extends to another signal
11966  {
11967  TPrefDirElement PDE = OR.GetFixedPrefDirElementAt(249, 0);
11968 // these will change at each element removal because OR is a reference to the real route
11969  int TVPos2 = PDE.GetTrackVectorPosition();
11970  if(FirstPass && (TVPos2 != FirstRouteElementVecPos)) //route is not directed away from cdt train, could be a call-on for another train (added at v2.8.0)
11971  {
11972  break;
11973  }
11974  TTrackElement TE2 = Track->TrackElementAt(1015, TVPos2);
11975  if(Track->TrackElementAt(1016, PDE.GetTrackVectorPosition()).Config[PDE.GetXLinkPos()] != Signal)
11976  {
11977  AllRoutes->RemoveRouteElement(24, TE2.HLoc, TE2.VLoc, PDE.GetELink());
11978  }
11979  else
11980  {
11981  break;
11982  }
11983  FirstPass = false;
11984  }
11985  AllRoutes->RebuildRailwayFlag = true;
11986  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to replot without stub route
11987  }
11988  }
11989  }
11990 // end of stub route removal addition
11991  }
11992  if(Train.MidElement > -1)
11993  {
11994  TrackElementPtr = &(Track->TrackElementAt(674, Train.MidElement));
11995  // remove TrainIDs from track element, added at v2.4.0
11996  if(TrackElementPtr->TrackType == Bridge)
11997  {
11998  if(Train.MidExitPos > 1)
11999  {
12000  TrackElementPtr->TrainIDOnBridgeTrackPos23 = -1;
12001  }
12002  else
12003  {
12004  TrackElementPtr->TrainIDOnBridgeTrackPos01 = -1;
12005  }
12006  }
12007  else
12008  {
12009  TrackElementPtr->TrainIDOnElement = -1;
12010  }
12011  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
12012  {
12013  TrackElementPtr->CallingOnSet = false;
12014  Track->PlotSignal(7, *TrackElementPtr, Display);
12015  }
12016 // [added at v1.3.0 as above]
12018  {
12019  RouteType = AllRoutes->GetRouteTypeAndNumber(28, Train.MidElement, Train.MidEntryPos, RouteNumber);
12020  if(RouteType == TAllRoutes::AutoSigsRoute)
12021  {
12024  }
12025  }
12026 // end of addition
12027  }
12028  if(Train.LeadElement > -1)
12029  // addition for v1.3.2 after Carwyn Thomas fault reported 24/05/15 - need to check if exiting at continuation (LeadElement == -1) as if so fails at next line
12030  {
12031  if(Track->TrackElementAt(675, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
12032  {
12033  TrackElementPtr = &(Track->TrackElementAt(676, Track->TrackElementAt(677, Train.LeadElement).Conn[Train.LeadExitPos]));
12034  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
12035  {
12036  TrackElementPtr->CallingOnSet = false;
12037  Track->PlotSignal(8, *TrackElementPtr, Display);
12038  }
12039  }
12040  }
12041  Train.LogAction(5, Train.HeadCode, "", RemoveTrain, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
12042  if(Train.ActionVectorEntryPtr->Command != "Frh") // if remaining at location no point in sending 'failed to terminate' message
12043  {
12044  Train.SendMissedActionLogs(0, -1, Train.ActionVectorEntryPtr); // -1 is a marker for send messages for all remaining
12045  } // entries, including Fer if present
12046 
12047  Utilities->CallLogPop(1200);
12048  }
12049  catch(const Exception &e)
12050  {
12051  ErrorLog(164, e.Message);
12052  }
12053 }
12054 
12055 // ---------------------------------------------------------------------------
12056 
12057 void __fastcall TInterface::ErrorButtonClick(TObject *Sender)
12058 // to terminate after error message given
12059 {
12060  ErrorMessage->Visible = false;
12061  ErrorMessageStoreImage->Visible = false;
12062  ErrorButton->Visible = false;
12063  Display->GetImage()->Visible = true;
12064  Application->Terminate();
12065 }
12066 
12067 // ---------------------------------------------------------------------------
12068 void __fastcall TInterface::PerformancePanelLabelStartDrag(TObject *Sender, TDragObject *&DragObject)
12069 {
12070  try
12071  {
12072  TrainController->LogEvent("PerformancePanelLabelStartDrag");
12073  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformancePanelLabelStartDrag");
12074  PerformancePanelDragStartX = Mouse->CursorPos.x - PerformancePanel->Left;
12075  PerformancePanelDragStartY = Mouse->CursorPos.y - PerformancePanel->Top;
12076  Utilities->CallLogPop(1202);
12077  }
12078  catch(const Exception &e)
12079  {
12080  ErrorLog(165, e.Message);
12081  }
12082 }
12083 // ---------------------------------------------------------------------------
12084 
12085 void __fastcall TInterface::FormClose(TObject *Sender, TCloseAction &Action)
12086 {
12087  try
12088  {
12089  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FormClose");
12090 /* Dropped at v2.9.1 as serves no apparent purpose
12091  if(!FileChangedFlag && !(Track->IsTrackFinished()) && (EveryPrefDir->PrefDirSize() > 0))
12092  {
12093  UnicodeString MessageStr =
12094  "Note that leaving the track unlinked will cause preferred directions to be lost on reloading. Prevent by linking the track then resaving. Do you still wish to exit?";
12095  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
12096  if(button == IDNO)
12097  {
12098  Action = caNone; // prevents form & application from closing
12099  Utilities->CallLogPop(1712);
12100  return;
12101  }
12102  }
12103 */
12105  {
12106  UnicodeString MessStr = "";
12108  {
12109  MessStr = UnicodeString("The railway and the timetable have both changed, exit without saving either?");
12110  }
12111  else if(FileChangedFlag)
12112  {
12113  MessStr = UnicodeString("The railway has changed, exit without saving?");
12114  }
12115  else
12116  {
12117  MessStr = UnicodeString("The timetable has changed, exit without saving?");
12118  }
12119  int button = Application->MessageBox(MessStr.c_str(), L"Please confirm", MB_YESNO);
12120  if(button == IDNO)
12121  {
12122  Action = caNone; // prevents form & application from closing
12123  Utilities->CallLogPop(1133);
12124  return;
12125  }
12126  }
12127  if(Level1Mode == OperMode)
12128  {
12130  {
12131  UnicodeString MessageStr = "Please note that the session will be lost if it hasn't been saved. Do you still wish to exit?";
12132  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
12134  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
12135  TrainController->BaseTime = TDateTime::CurrentDateTime();
12137  if(button == IDNO)
12138  {
12139  Action = caNone; // prevents form & application from closing
12140  Utilities->CallLogPop(969);
12141  return;
12142  }
12143  }
12145  Utilities->PerformanceFile.close();
12146  }
12147  if((TempTTFileName != "") && FileExists(TempTTFileName))
12148  {
12149  DeleteFile(TempTTFileName);
12150  }
12151  Utilities->CallLogPop(971);
12152  }
12153  catch(const Exception &e)
12154  {
12155  ErrorLog(166, e.Message);
12156  }
12157 }
12158 
12159 // ---------------------------------------------------------------------------
12160 
12161 void __fastcall TInterface::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
12162 {
12163 // TrainController->LogEvent("FormKeyDown," + AnsiString(Key));
12164 // drop event log as have too many spurious entries
12165  try
12166  {
12167  if((Shift.Contains(ssAlt)) && (Shift.Contains(ssCtrl)))
12168  {
12169  if(Key == '2')
12170  {
12171  if(CallLogTickerLabel->Visible)
12172  {
12173  CallLogTickerLabel->Visible = false;
12174  }
12175  else
12176  {
12177  CallLogTickerLabel->Visible = true;
12178  }
12179  }
12180  else if(Key == '3')
12181  {
12182  if(DevelopmentPanel->Visible)
12183  {
12184  DevelopmentPanel->Visible = false;
12185  }
12186  else
12187  {
12188  DevelopmentPanel->Visible = true;
12189  DevelopmentPanel->BringToFront();
12190  }
12191  }
12192  else if(Key == '4')
12193  {
12194  TestFunction();
12195  }
12196  else if(Key == '5')
12197  {
12198  TMsgDlgButtons Buttons;
12199  Buttons << mbYes << mbNo;
12200  if(MessageDlg("Do you wish to allow facing signals next to bridges? If so please be aware that routes cannot be truncated to these signals.",
12201  mtWarning, Buttons, 0) == mrYes)
12202  {
12204  }
12205  else
12206  {
12208  }
12209  }
12210  }
12211  else if(Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
12212  {
12213  CtrlKey = true;
12214  }
12215  else if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
12216  {
12217  ShiftKey = true;
12218  }
12219 // below added at v1.3.0 to allow keyboard scrolling as well as mouse button scrolling - see user suggestion on Features & Requests forum 30/09/12
12220 // the NonCTRLOrSHIFTKeyUpFlag prevents repeated viewpoint movements without keys being re-pressed
12221 // note that use the OnKeyDown event rather than OnKeyPress as suggested by the user so that the CTRL & SHIFT keys can be taken into account
12222 
12223 // at v2.4.2 the flag changed to LastNonCtrlOrShiftKeyDown to make condition specific to last key, because when a message given the key up event
12224 // is not seen as the form does not have focus, so with the flag no shortcut key will work on the first press, with this only the same shortcut key
12225 // won't work on first press and that is less likely to be used a second time on either side of the message
12226 
12227  if((Key != VK_SHIFT) && (Key != VK_CONTROL))
12228  {
12229  if(LastNonCtrlOrShiftKeyDown == Key) // same key still down rejected
12230  {
12231  return;
12232  }
12233  else
12234  {
12236  }
12237  }
12238  if(Key == VK_UP)
12239  {
12240  if(ScreenUpButton->Enabled)
12241  {
12242  ScreenUpButton->Click();
12243  }
12244  }
12245  else if(Key == VK_DOWN)
12246  {
12247  if(ScreenDownButton->Enabled)
12248  {
12249  ScreenDownButton->Click();
12250  }
12251  }
12252  else if(Key == VK_LEFT)
12253  {
12254  if(ScreenLeftButton->Enabled)
12255  {
12256  ScreenLeftButton->Click();
12257  }
12258  }
12259  else if(Key == VK_RIGHT)
12260  {
12261  if(ScreenRightButton->Enabled)
12262  {
12263  ScreenRightButton->Click();
12264  }
12265  }
12266  else if(Key == VK_HOME)
12267  {
12268  if(HomeButton->Enabled)
12269  {
12270  HomeButton->Click();
12271  }
12272  }
12273 // end of 1.3.0 addition
12274  else if(Key == VK_END) // added at v2.2.0 to toggle zoom using 'End' key
12275  {
12276  if(ZoomButton->Enabled)
12277  {
12278  ZoomButton->Click();
12279  }
12280  }
12281  else if(Key == VK_END) // added at v2.2.0 to toggle zoom using 'End' key
12282  {
12283  if(ZoomButton->Enabled)
12284  {
12285  ZoomButton->Click();
12286  }
12287  }
12288 // below added for v2.4.2 to add more keyboard shortcuts
12289  if(DistanceBox->Focused() || SpeedLimitBox->Focused() || MileEdit->Focused() || ChainEdit->Focused() || YardEdit->Focused() ||
12290  SpeedEditBox2->Focused() || MTBFEditBox->Focused() || LocationNameTextBox->Focused() || TextBox->Focused() || PowerEditBox->Focused() ||
12291  SpeedEditBox->Focused() || AddSubMinsBox->Focused() || OneEntryTimetableMemo->Focused())
12292  {
12293  // prevent letter keys interfering when these boxes have focus - many are mutually exclusive but include them all
12294  return;
12295  }
12296  if(Shift.Contains(ssShift) && !Shift.Contains(ssAlt) && !Shift.Contains(ssCtrl) && NewHomeButton->Enabled && NewHomeButton->Visible)
12297  {
12298  if(Level1Mode != TimetableMode && (Key == 'H' || Key == 'h')) // TimetablePanel uses Shift H too so disable this when it's in use
12299  {
12300  NewHomeButton->Click();
12301  }
12302  }
12303 // Operating panel
12304  if(Level1Mode == OperMode && OperatingPanel->Enabled && OperatingPanel->Visible && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
12305  {
12306  // use Shift.Contains(ssShift etc instead of ShiftKey as that not set if pressed second after Ctrl key pressed
12307  if(!Shift.Contains(ssCtrl))
12308  {
12309  if(OperateButton->Visible && OperateButton->Enabled)
12310  {
12311  if(Level2OperMode == Operating && (Key == 'P' || Key == 'p'))
12312  {
12313  OperateButton->Click();
12314  }
12315  else if((Level2OperMode == Paused || Level2OperMode == PreStart) && (Key == 'R' || Key == 'r'))
12316  {
12317  OperateButton->Click();
12318  }
12319  }
12320  if(PresetAutoSigRoutesButton->Visible && PresetAutoSigRoutesButton->Enabled && (Key == 'A' || Key == 'a'))
12321  {
12322  PresetAutoSigRoutesButton->Click();
12323  }
12324  if(PerformanceLogButton->Visible && PerformanceLogButton->Enabled && (Key == 'L' || Key == 'l'))
12325  {
12326  PerformanceLogButton->Click();
12327  }
12328  if(CallingOnButton->Visible && CallingOnButton->Enabled && (Key == 'O' || Key == 'o'))
12329  {
12330  CallingOnButton->Click();
12331  }
12332  if(OperatorActionButton->Visible && OperatorActionButton->Enabled && (Key == 'D' || Key == 'd'))
12333  {
12334  OperatorActionButton->Click();
12335  }
12336  if(RouteCancelButton->Visible && RouteCancelButton->Enabled && (Key == 'C' || Key == 'c'))
12337  {
12338  RouteCancelButton->Click();
12339  }
12340  if(TTClockAdjButton->Visible && TTClockAdjButton->Enabled && (Key == 'T' || Key == 't'))
12341  {
12342  TTClockAdjButton->Click();
12343  }
12344  if(AutoSigsButton->Visible && AutoSigsButton->Enabled && Key == '1') // route buttons - autosigs
12345  {
12346  AutoSigsButton->Click();
12347  }
12348  if(SigPrefConsecButton->Visible && SigPrefConsecButton->Enabled && Key == '2') // route buttons - prefdir
12349  {
12350  SigPrefConsecButton->Click();
12351  }
12352  if(SigPrefNonConsecButton->Visible && SigPrefNonConsecButton->Enabled && Key == '4') // added at v2.7.0 for prefdir & any following signal
12353  {
12354  SigPrefNonConsecButton->Click();
12355  }
12356  if(UnrestrictedButton->Visible && UnrestrictedButton->Enabled && Key == '3') // route buttons - unrestricted
12357  {
12358  UnrestrictedButton->Click();
12359  }
12360  if(ExitOperationButton->Visible && ExitOperationButton->Enabled && Key == '\x1b')
12361  {
12362  ExitOperationButton->Click();
12363  }
12364  }
12365  else // CtrlKey down
12366  {
12367  if(SaveSessionButton->Visible && SaveSessionButton->Enabled)
12368  {
12369  SaveMenuItem->ShortCut = 0;
12370 // It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
12371  if(Key == 'S' || Key == 's') // so this will never execute
12372  {
12373  SaveSessionButton->Click();
12374  }
12375  }
12376  }
12377  }
12378 // Timetable clock adjust panel
12379  if(Level1Mode == OperMode && TTClockAdjPanel->Enabled && TTClockAdjPanel->Visible && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
12380  {
12381  // use Shift.Contains(ssShift etc instead of ShiftKey as that not set if pressed second after Ctrl key pressed
12382  if(Shift.Contains(ssShift))
12383  {
12384  if(TTClockExitButton->Visible && TTClockExitButton->Enabled && (Key == 'A' || Key == 'a'))
12385  {
12386  TTClockExitButton->Click();
12387  }
12388  if(TTClockResetButton->Visible && TTClockResetButton->Enabled && (Key == 'R' || Key == 'r'))
12389  {
12390  TTClockResetButton->Click();
12391  }
12392  }
12393  }
12394 // Track build panel
12395  if((Level1Mode == TrackMode) && TrackBuildPanel->Visible && TrackBuildPanel->Enabled)
12396  {
12397  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
12398  {
12399  if(AddTrackButton->Visible && AddTrackButton->Enabled && (Key == 'A' || Key == 'a')) // add/remove track elements
12400  {
12401  AddTrackButton->Click();
12402  }
12403  if(SigAspectButton->Visible && SigAspectButton->Enabled && (Key == 'S' || Key == 's')) // cycle through signal aspects
12404  {
12405  SigAspectButton->Click();
12406  }
12407  if(TrackOKButton->Visible && TrackOKButton->Enabled && (Key == 'L' || Key == 'l')) // link track
12408  {
12409  TrackOKButton->Click();
12410  }
12411  if(FontButton->Visible && FontButton->Enabled && (Key == 'F' || Key == 'f')) // change font
12412  {
12413  FontButton->Click();
12414  }
12415  if(LocationNameButton->Visible && LocationNameButton->Enabled && (Key == 'N' || Key == 'n')) // name locations
12416  {
12417  LocationNameButton->Click();
12418  }
12419  if(SetLengthsButton->Visible && SetLengthsButton->Enabled && (Key == 'D' || Key == 'd')) // set distances/speeds
12420  {
12421  SetLengthsButton->Click();
12422  }
12423  if(AddTextButton->Visible && AddTextButton->Enabled && (Key == 'T' || Key == 't')) // add text
12424  {
12425  AddTextButton->Click();
12426  }
12427  if(ScreenGridButton->Visible && ScreenGridButton->Enabled && (Key == 'G' || Key == 'g')) // toggle grid
12428  {
12429  ScreenGridButton->Click();
12430  }
12431  if(MoveTextOrGraphicButton->Visible && MoveTextOrGraphicButton->Enabled && (Key == 'M' || Key == 'm')) // move text or graphic
12432  {
12433  MoveTextOrGraphicButton->Click();
12434  }
12435  if(UserGraphicButton->Visible && UserGraphicButton->Enabled && (Key == 'I' || Key == 'i')) // insert image
12436  {
12437  UserGraphicButton->Click();
12438  }
12439  if(SetGapsButton->Visible && SetGapsButton->Enabled && (Key == 'J' || Key == 'j')) // join gaps
12440  {
12441  SetGapsButton->Click();
12442  }
12443  }
12444  if(Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
12445  {
12446  if(SaveRailwayTBPButton->Visible && SaveRailwayTBPButton->Enabled) // save railway in trackbuild mode
12447  {
12448  SaveMenuItem->ShortCut = 0;
12449 // It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
12450  if(Key == 'S' || Key == 's') // so this will never execute
12451  {
12452  SaveRailwayTBPButton->Click();
12453  }
12454  }
12455  }
12456  if(!Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
12457  {
12458  if((ExitTrackButton->Visible && ExitTrackButton->Enabled) && Key == '\x1b') // escape key
12459  {
12460  ExitTrackButton->Click();
12461  }
12462  }
12463  }
12464 // PrefDir panel
12465  if(Level1Mode == PrefDirMode && PrefDirPanel->Visible && PrefDirPanel->Enabled && !Shift.Contains(ssAlt))
12466  {
12467  if(!Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
12468  {
12469  if((ExitPrefDirButton->Visible && ExitPrefDirButton->Enabled) && Key == '\x1b') // escape key
12470  {
12471  ExitPrefDirButton->Click();
12472  }
12473  }
12474  if(!Shift.Contains(ssShift) && Shift.Contains(ssCtrl))
12475  {
12476  if(SaveRailwayPDPButton->Visible && SaveRailwayPDPButton->Enabled)
12477  {
12478  SaveMenuItem->ShortCut = 0;
12479 // It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
12480  if(Key == 'S' || Key == 's') // so this will never execute
12481  {
12482  SaveRailwayPDPButton->Click();
12483  }
12484  }
12485  }
12486  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
12487  {
12488  if(AddPrefDirButton->Visible && AddPrefDirButton->Enabled && (Key == 'A' || Key == 'a')) // add pref dir
12489  {
12490  AddPrefDirButton->Click();
12491  }
12492  if(DeleteOnePrefDirButton->Visible && DeleteOnePrefDirButton->Enabled && (Key == 'D' || Key == 'd')) // delete one pref dir
12493  {
12494  DeleteOnePrefDirButton->Click();
12495  }
12496  if(DeleteAllPrefDirButton->Visible && DeleteAllPrefDirButton->Enabled && (Key == 'C' || Key == 'c')) // delete all pref dirs
12497  {
12498  DeleteAllPrefDirButton->Click();
12499  }
12500  }
12501  }
12502 // Note that save button in BaseMode is handled by Ctrl S from the File menu
12503 
12504 // Timetable panel
12505  if(Level1Mode == TimetableMode && TimetablePanel->Visible && TimetablePanel->Enabled && !Shift.Contains(ssAlt))
12506  {
12507  if(!Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
12508  {
12509  if(ExitTTModeButton->Visible && ExitTTModeButton->Enabled && Key == '\x1b') // escape key
12510  {
12511  ExitTTModeButton->Click();
12512  }
12513  }
12514  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl)) // show/hide timetable edit panel
12515  {
12516  if(ShowHideTTButton->Visible && ShowHideTTButton->Enabled)
12517  {
12518  if(!TimetableEditPanel->Visible)
12519  {
12520  if(Key == 'S' || Key == 's')
12521  {
12522  ShowHideTTButton->Click();
12523  }
12524  }
12525  else if(Key == 'H' || Key == 'h')
12526  {
12527  ShowHideTTButton->Click();
12528  }
12529  }
12530  }
12531  }
12532 // Timetable edit panel
12533 // These just set flags. The corresponding 'Click()' function executes separately to the keypress because Windows stores the key until after any directly linked key code
12534 // is executed then selects the timetable entry that begins with the letter corresponding to the key. Without this separation the list box is left with the wrong entry
12535 // showing. See DevHistory.txt for the version at v2.5.0 for details.
12536  if(Level1Mode == TimetableMode && TimetableEditPanel->Visible && TimetableEditPanel->Enabled && !Shift.Contains(ssAlt))
12537  {
12538  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
12539  {
12541 // store value here before the Windows key press function runs (it runs after any local code)
12542  if(PreviousTTEntryButton->Enabled && (Key == 'L' || Key == 'l'))
12543  {
12544  PreviousTTEntryKeyFlag = true;
12545  }
12546  if(NextTTEntryButton->Enabled && (Key == 'N' || Key == 'n'))
12547  {
12548  NextTTEntryKeyFlag = true;
12549  }
12550  if(MoveTTEntryUpButton->Enabled && (Key == 'U' || Key == 'u'))
12551  {
12552  MoveTTEntryUpKeyFlag = true;
12553  }
12554  if(MoveTTEntryDownButton->Enabled && (Key == 'D' || Key == 'd'))
12555  {
12556  MoveTTEntryDownKeyFlag = true;
12557  }
12558  if(CopyTTEntryButton->Enabled && (Key == 'C' || Key == 'c'))
12559  {
12560  CopyTTEntryKeyFlag = true;
12561  }
12562  if(CutTTEntryButton->Enabled && (Key == 'X' || Key == 'x'))
12563  {
12564  CutTTEntryKeyFlag = true;
12565  }
12566  if(PasteTTEntryButton->Enabled && (Key == 'P' || Key == 'p'))
12567  {
12568  PasteTTEntryKeyFlag = true;
12569  }
12570  if(DeleteTTEntryButton->Enabled && (Key == 'E' || Key == 'e'))
12571  {
12572  DeleteTTEntryKeyFlag = true;
12573  }
12574 /* if(SaveTTEntryButton->Enabled && (Key == 'E' || Key == 'e')) //can't have save while editing entry as adds the letter to the entry
12575  {
12576  SaveTTEntryKeyFlag = true;
12577  }
12578  if(CancelTTActionButton->Enabled && (Key == 'K' || Key == 'k')) //can't have cancel while editing entry as adds the letter to the entry
12579  {
12580  CancelTTActionKeyFlag = true;
12581  }
12582 */
12583  if(NewTTEntryButton->Enabled && (Key == 'I' || Key == 'i'))
12584  {
12585  NewTTEntryKeyFlag = true;
12586  }
12587  if(AZOrderButton->Enabled && (Key == 'Z' || Key == 'z'))
12588  {
12589  AZOrderKeyFlag = true;
12590  }
12591 /*
12592  if(AddMinsButton->Enabled && (Key == 'M' || Key == 'm')) //can't have key here as adds the letter to the entry
12593  {
12594  AddMinsKeyFlag = true;
12595  }
12596  if(SubMinsButton->Enabled && (Key == 'B' || Key == 'b')) //can't have key here as adds the letter to the entry
12597  {
12598  SubMinsKeyFlag = true;
12599  }
12600 */
12601  if(TTServiceSyntaxCheckButton->Enabled && (Key == 'Q' || Key == 'q'))
12602  {
12604  }
12605  if(ValidateTimetableButton->Enabled && (Key == 'V' || Key == 'v'))
12606  {
12607  ValidateTimetableKeyFlag = true;
12608  }
12609  if(SaveTTButton->Enabled && (Key == 'T' || Key == 't'))
12610  {
12611  SaveTTKeyFlag = true;
12612  }
12613  if(SaveTTAsButton->Enabled && (Key == 'A' || Key == 'a'))
12614  {
12615  SaveTTAsKeyFlag = true;
12616  }
12617  if(RestoreTTButton->Enabled && (Key == 'R' || Key == 'r'))
12618  {
12619  RestoreTTKeyFlag = true;
12620  }
12621  if(ExportTTButton->Enabled && (Key == 'O' || Key == 'o'))
12622  {
12623  ExportTTKeyFlag = true;
12624  }
12625  if(ConflictAnalysisButton->Enabled && (Key == 'F' || Key == 'f'))
12626  {
12627  ConflictAnalysisKeyFlag = true;
12628  }
12629  }
12630  }
12631 // Information menu
12632  if(FloatingInfoMenu->Enabled && !Shift.Contains(ssAlt) && Shift.Contains(ssCtrl) && Shift.Contains(ssShift))
12633  {
12634  if(Key == 'I' || Key == 'i') // toggle track info
12635  {
12636  TrackInfoOnOffMenuItem->Click();
12637  }
12638  else if(TrainInfoMenuItem->Enabled)
12639  {
12640  if(Key == 'S' || Key == 's') // toggle train status info
12641  {
12643  }
12644  else if(Key == 'T' || Key == 't') // toggle train timetable info
12645  {
12646  TrainTTInfoOnOffMenuItem->Click();
12647  }
12648  }
12649  }
12650 // end of 2.4.2 addition
12651 
12652  }
12653  catch(const Exception &e)
12654  {
12655  ErrorLog(167, e.Message);
12656  }
12657 }
12658 
12659 // ---------------------------------------------------------------------------
12660 
12661 void __fastcall TInterface::FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
12662 {
12663  if((Key != VK_SHIFT) && (Key != VK_CONTROL))
12664  {
12665  LastNonCtrlOrShiftKeyDown = -1; // reset value to no key down
12666  }
12667  CtrlKey = false;
12668  ShiftKey = false;
12669  SaveMenuItem->ShortCut = 16467; // restore Ctrl S for save menu in case set to 0 in FormKeyDown
12670 }
12671 
12672 // ---------------------------------------------------------------------------
12673 
12674 void __fastcall TInterface::OutputLog1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
12675 {
12676  if((Button == mbRight) && Level2OperMode == Operating)
12677  {
12678  OutputLog1->Caption = "";
12679  }
12680 }
12681 
12682 // ---------------------------------------------------------------------------
12683 
12684 void __fastcall TInterface::OutputLog2MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
12685 {
12686  if((Button == mbRight) && Level2OperMode == Operating)
12687  {
12688  OutputLog2->Caption = "";
12689  }
12690 }
12691 // ---------------------------------------------------------------------------
12692 
12693 void __fastcall TInterface::OutputLog3MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
12694 {
12695  if((Button == mbRight) && Level2OperMode == Operating)
12696  {
12697  OutputLog3->Caption = "";
12698  }
12699 }
12700 
12701 // ---------------------------------------------------------------------------
12702 
12703 void __fastcall TInterface::OutputLog4MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
12704 {
12705  if((Button == mbRight) && Level2OperMode == Operating)
12706  {
12707  OutputLog4->Caption = "";
12708  }
12709 }
12710 
12711 // ---------------------------------------------------------------------------
12712 
12713 void __fastcall TInterface::OutputLog5MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
12714 {
12715  if((Button == mbRight) && Level2OperMode == Operating)
12716  {
12717  OutputLog5->Caption = "";
12718  }
12719 }
12720 // ---------------------------------------------------------------------------
12721 
12722 void __fastcall TInterface::OutputLog6MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
12723 {
12724  if((Button == mbRight) && Level2OperMode == Operating)
12725  {
12726  OutputLog6->Caption = "";
12727  }
12728 }
12729 
12730 // ---------------------------------------------------------------------------
12731 
12732 void __fastcall TInterface::OutputLog7MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
12733 {
12734  if((Button == mbRight) && Level2OperMode == Operating)
12735  {
12736  OutputLog7->Caption = "";
12737  }
12738 }
12739 
12740 // ---------------------------------------------------------------------------
12741 
12742 void __fastcall TInterface::OutputLog8MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
12743 {
12744  if((Button == mbRight) && Level2OperMode == Operating)
12745  {
12746  OutputLog8->Caption = "";
12747  }
12748 }
12749 
12750 // ---------------------------------------------------------------------------
12751 
12752 void __fastcall TInterface::OutputLog9MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
12753 {
12754  if((Button == mbRight) && Level2OperMode == Operating)
12755  {
12756  OutputLog9->Caption = "";
12757  }
12758 }
12759 
12760 // ---------------------------------------------------------------------------
12761 
12762 void __fastcall TInterface::OutputLog10MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
12763 {
12764  if((Button == mbRight) && Level2OperMode == Operating)
12765  {
12766  OutputLog10->Caption = "";
12767  }
12768 }
12769 
12770 // ---------------------------------------------------------------------------
12771 
12772 void __fastcall TInterface::AboutMenuItemClick(TObject *Sender)
12773 {
12774  try
12775  {
12776  if((Level1Mode == OperMode) && (Level2OperMode != PreStart))
12777  // if PreStart leave as is [Modified at v1.2.0 - formerly just 'if((Level1Mode == OperMode)']
12778  {
12780  SetLevel2OperMode(3);
12781  MasterClock->Enabled = false;
12782  }
12783  AboutForm->ShowModal();
12784  }
12785  catch(const Exception &e)
12786  {
12787  ErrorLog(168, e.Message);
12788  }
12789 }
12790 
12791 // ---------------------------------------------------------------------------
12792 
12793 void __fastcall TInterface::OpenHelpMenuItemClick(TObject *Sender)
12794 {
12795  try
12796  {
12797  // Helpfile allocated during construction of Interface
12798  Application->HelpKeyword(u"Introduction"); // added at v2.0.0 for .chm help file
12799  }
12800  catch(const Exception &e)
12801  {
12802  ErrorLog(175, e.Message);
12803  }
12804 }
12805 
12806 // ---------------------------------------------------------------------------
12807 
12808 void __fastcall TInterface::RailwayWebSiteMenuItemClick(TObject *Sender)
12809 {
12810  const UnicodeString Link = "http://www.railwayoperationsimulator.com";
12811  ::ShellExecute(Handle, NULL, (Link).c_str(), NULL, NULL, SW_SHOWNORMAL);
12812 }
12813 
12814 // ---------------------------------------------------------------------------
12815 
12816 void __fastcall TInterface::BlackBgndMenuItemClick(TObject *Sender)
12817 {
12818  try
12819  {
12820  TrainController->LogEvent("BlackBgndMenuItemClick");
12821  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BlackBgndMenuItemClick");
12822  TColor OldTransparentColour = Utilities->clTransparent;
12823  Utilities->clTransparent = TColor(0);
12824  SelectBitmap->TransparentColor = Utilities->clTransparent;
12827 
12828  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
12829  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
12830  Level1Mode = BaseMode;
12831  SetLevel1Mode(128);
12832  Utilities->CallLogPop(1797);
12833  }
12834  catch(const Exception &e)
12835  {
12836  ErrorLog(170, e.Message);
12837  }
12838 }
12839 
12840 // ---------------------------------------------------------------------------
12841 
12842 void __fastcall TInterface::WhiteBgndMenuItemClick(TObject *Sender)
12843 {
12844  try
12845  {
12846  TrainController->LogEvent("WhiteBgndMenuItemClick");
12847  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",WhiteBgndMenuItemClick");
12848  TColor OldTransparentColour = Utilities->clTransparent;
12849  Utilities->clTransparent = TColor(0xFFFFFF);
12850  SelectBitmap->TransparentColor = Utilities->clTransparent;
12853 
12854  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
12855  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
12856  Level1Mode = BaseMode;
12857  SetLevel1Mode(129);
12858  Utilities->CallLogPop(1798);
12859  }
12860  catch(const Exception &e)
12861  {
12862  ErrorLog(171, e.Message);
12863  }
12864 }
12865 
12866 // ---------------------------------------------------------------------------
12867 
12868 void __fastcall TInterface::BlueBgndMenuItemClick(TObject *Sender)
12869 {
12870  try
12871  {
12872  TrainController->LogEvent("BlueBgndMenuItemClick");
12873  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BlueBgndMenuItemClick");
12874  TColor OldTransparentColour = Utilities->clTransparent;
12875  Utilities->clTransparent = TColor(0x330000);
12876  SelectBitmap->TransparentColor = Utilities->clTransparent;
12879 
12880  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
12881  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
12882  Level1Mode = BaseMode;
12883  SetLevel1Mode(130);
12884  Utilities->CallLogPop(1799);
12885  }
12886  catch(const Exception &e)
12887  {
12888  ErrorLog(172, e.Message);
12889  }
12890 }
12891 
12892 // ---------------------------------------------------------------------------
12893 
12894 void __fastcall TInterface::SpeedToggleButtonClick(TObject *Sender)
12895 {
12896  if(SpeedTopLabel->Caption == "mph")
12897  {
12898  SpeedTopLabel->Caption = "km/h";
12899  SpeedBottomLabel->Caption = "mph";
12900  }
12901  else
12902  {
12903  SpeedTopLabel->Caption = "mph";
12904  SpeedBottomLabel->Caption = "km/h";
12905  }
12906  // swap values to match toggle state
12907  UnicodeString SavedTopValue = SpeedEditBox->Text;
12908  UnicodeString SavedBottomValue = SpeedVariableLabel->Caption;
12909 
12910  SpeedEditBox->Text = SavedBottomValue;
12911  SpeedVariableLabel->Caption = SavedTopValue;
12912 }
12913 // ---------------------------------------------------------------------------
12914 
12915 void __fastcall TInterface::SpeedToggleButton2Click(TObject *Sender)
12916 {
12917  if(SpeedTopLabel2->Caption == "mph")
12918  {
12919  SpeedTopLabel2->Caption = "km/h";
12920  SpeedBottomLabel2->Caption = "mph";
12921  }
12922  else
12923  {
12924  SpeedTopLabel2->Caption = "mph";
12925  SpeedBottomLabel2->Caption = "km/h";
12926  }
12927  // swap values to match toggle state
12928  UnicodeString SavedTopValue = SpeedEditBox2->Text;
12929  UnicodeString SavedBottomValue = SpeedVariableLabel2->Caption;
12930 
12931  SpeedEditBox2->Text = SavedBottomValue;
12932  SpeedVariableLabel2->Caption = SavedTopValue;
12933 }
12934 // ---------------------------------------------------------------------------
12935 
12936 void __fastcall TInterface::SpeedEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
12937 {
12938  try
12939  {
12940  TrainController->LogEvent("SpeedEditBoxKeyUp," + AnsiString(Key));
12941  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedEditBoxKeyUp," + AnsiString(Key));
12942  bool ErrorFlag = false, TooBigFlag = false;
12943  if(SpeedEditBox->Text.Length() > 0)
12944  {
12945  if(SpeedEditBox->Text.Length() > 5)
12946  {
12947  TooBigFlag = true;
12948  }
12949  for(int x = 1; x <= SpeedEditBox->Text.Length(); x++)
12950  {
12951  if((SpeedEditBox->Text[x] < '0') || (SpeedEditBox->Text[x] > '9'))
12952  {
12953  SpeedVariableLabel->Caption = "Entry error";
12954  ErrorFlag = true;
12955  break;
12956  }
12957  if(TooBigFlag)
12958  {
12959  SpeedVariableLabel->Caption = "Too big";
12960  break;
12961  }
12962  }
12963  if(!ErrorFlag && !TooBigFlag)
12964  {
12965 /*
12966  1 mph = 1.609344 km/h
12967  1 km/h = 0.621371 mph
12968 */
12969  if(SpeedTopLabel->Caption == "mph")
12970  {
12971  // do mph-to-km/h conversion
12972  int MPH = SpeedEditBox->Text.ToInt();
12973  int KPH = (MPH * 1.609344) + 0.5;
12974  SpeedVariableLabel->Caption = UnicodeString(KPH);
12975  }
12976  else
12977  {
12978  // do km/h-to-mph conversion
12979  int KPH = SpeedEditBox->Text.ToInt();
12980  int MPH = (KPH * 0.621371) + 0.5;
12981  SpeedVariableLabel->Caption = UnicodeString(MPH);
12982  }
12983  }
12984  }
12985  else
12986  {
12987  SpeedVariableLabel->Caption = "";
12988  }
12989  Utilities->CallLogPop(1865);
12990  }
12991  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash //non-error catch
12992  {
12993  SpeedVariableLabel->Caption = "Entry error";
12994  Utilities->CallLogPop(2307);
12995  }
12996  catch(const Exception &e)
12997  {
12998  ErrorLog(176, e.Message);
12999  }
13000 }
13001 
13002 // ---------------------------------------------------------------------------
13003 
13004 void __fastcall TInterface::PowerToggleButtonClick(TObject *Sender)
13005 {
13006  if(PowerTopLabel->Caption == "HP")
13007  {
13008  PowerTopLabel->Caption = "kW";
13009  PowerBottomLabel->Caption = "HP";
13010  }
13011  else
13012  {
13013  PowerTopLabel->Caption = "HP";
13014  PowerBottomLabel->Caption = "kW";
13015  }
13016  // swap values to match toggle state
13017  UnicodeString SavedTopValue = PowerEditBox->Text;
13018  UnicodeString SavedBottomValue = PowerVariableLabel->Caption;
13019 
13020  PowerEditBox->Text = SavedBottomValue;
13021  PowerVariableLabel->Caption = SavedTopValue;
13022 }
13023 // ---------------------------------------------------------------------------
13024 
13025 void __fastcall TInterface::PowerEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
13026 {
13027  try
13028  {
13029  TrainController->LogEvent("PowerEditBoxKeyUp," + AnsiString(Key));
13030  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PowerEditBoxKeyUp," + AnsiString(Key));
13031  bool ErrorFlag = false, TooBigFlag = false;
13032  if(PowerEditBox->Text.Length() > 0)
13033  {
13034  if(PowerEditBox->Text.Length() > 8)
13035  {
13036  TooBigFlag = true;
13037  }
13038  for(int x = 1; x <= PowerEditBox->Text.Length(); x++)
13039  {
13040  if((PowerEditBox->Text[x] < '0') || (PowerEditBox->Text[x] > '9'))
13041  {
13042  PowerVariableLabel->Caption = "Entry error";
13043  ErrorFlag = true;
13044  break;
13045  }
13046  if(TooBigFlag)
13047  {
13048  PowerVariableLabel->Caption = "Too big";
13049  break;
13050  }
13051  }
13052  if(!ErrorFlag && !TooBigFlag)
13053  {
13054 /*
13055  1 kW = 1.340482574 HP
13056  1 HP = 0.745699872 kW
13057 */
13058  if(PowerTopLabel->Caption == "HP")
13059  {
13060  // do HP-to-kW conv
13061  int HP = PowerEditBox->Text.ToInt();
13062  int KW = (HP * 0.745699872) + 0.5;
13063  PowerVariableLabel->Caption = UnicodeString(KW);
13064  }
13065  else
13066  {
13067  // do kW-to-HP conv
13068  int KW = PowerEditBox->Text.ToInt();
13069  int HP = (KW * 1.340482574) + 0.5;
13070  PowerVariableLabel->Caption = UnicodeString(HP);
13071  }
13072  }
13073  }
13074  else
13075  {
13076  PowerVariableLabel->Caption = "";
13077  }
13078  Utilities->CallLogPop(1868);
13079  }
13080  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash //non-error catch
13081  {
13082  PowerVariableLabel->Caption = "Entry error";
13083  Utilities->CallLogPop(2308);
13084  }
13085  catch(const Exception &e)
13086  {
13087  ErrorLog(179, e.Message);
13088  }
13089 }
13090 // ---------------------------------------------------------------------------
13091 
13092 void __fastcall TInterface::SpeedEditBox2KeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
13093 {
13094  try
13095  {
13096  TrainController->LogEvent("SpeedEditBox2KeyUp," + AnsiString(Key));
13097  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedEditBox2KeyUp," + AnsiString(Key));
13098  bool ErrorFlag = false, TooBigFlag = false;
13099  if(SpeedEditBox2->Text.Length() > 0)
13100  {
13101  if(SpeedEditBox2->Text.Length() > 5)
13102  {
13103  TooBigFlag = true;
13104  }
13105  for(int x = 1; x <= SpeedEditBox2->Text.Length(); x++)
13106  {
13107  if((SpeedEditBox2->Text[x] < '0') || (SpeedEditBox2->Text[x] > '9'))
13108  {
13109  SpeedVariableLabel2->Caption = "Entry error";
13110  ErrorFlag = true;
13111  break;
13112  }
13113  if(TooBigFlag)
13114  {
13115  SpeedVariableLabel2->Caption = "Too big";
13116  break;
13117  }
13118  }
13119  if(!ErrorFlag && !TooBigFlag)
13120  {
13121 /*
13122  1 mph = 1.609344 km/h
13123  1 km/h = 0.621371 mph
13124 */
13125  if(SpeedTopLabel2->Caption == "mph")
13126  {
13127  // do mph-to-km/h conversion
13128  int MPH = SpeedEditBox2->Text.ToInt();
13129  int KPH = (MPH * 1.609344) + 0.5;
13130  SpeedVariableLabel2->Caption = AnsiString(KPH);
13131  }
13132  else
13133  {
13134  // do km/h-to-mph conversion
13135  int KPH = SpeedEditBox2->Text.ToInt();
13136  int MPH = (KPH * 0.621371) + 0.5;
13137  SpeedVariableLabel2->Caption = AnsiString(MPH);
13138  }
13139  }
13140  }
13141  else
13142  {
13143  SpeedVariableLabel2->Caption = "";
13144  }
13145  Utilities->CallLogPop(1866);
13146  }
13147  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash //non-error catch
13148  {
13149  SpeedVariableLabel2->Caption = "Entry error";
13150  Utilities->CallLogPop(2309);
13151  }
13152  catch(const Exception &e)
13153  {
13154  ErrorLog(177, e.Message);
13155  }
13156 }
13157 
13158 // ---------------------------------------------------------------------------
13159 
13160 void __fastcall TInterface::LengthEditKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
13161 {
13162  try
13163  {
13164  TrainController->LogEvent("LengthEditKeyUp," + AnsiString(Key));
13165  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthEditKeyUp," + AnsiString(Key));
13166  bool ErrorFlag = false, TooLongFlag = false;
13167  if((MileEdit->Text.Length() > 0) && (MileEdit->Text.Length() < 6))
13168  {
13169  for(int x = 1; x <= MileEdit->Text.Length(); x++)
13170  {
13171  if((MileEdit->Text[x] < '0') || (MileEdit->Text[x] > '9'))
13172  {
13173  MetreVariableLabel->Caption = "Entry error";
13174  ErrorFlag = true;
13175  break;
13176  }
13177  }
13178  }
13179  if((ChainEdit->Text.Length() > 0) && (ChainEdit->Text.Length() < 6))
13180  {
13181  for(int x = 1; x <= ChainEdit->Text.Length(); x++)
13182  {
13183  if((ChainEdit->Text[x] < '0') || (ChainEdit->Text[x] > '9'))
13184  {
13185  MetreVariableLabel->Caption = "Entry error";
13186  ErrorFlag = true;
13187  break;
13188  }
13189  }
13190  }
13191  if((YardEdit->Text.Length() > 0) && (YardEdit->Text.Length() < 6))
13192  {
13193  for(int x = 1; x <= YardEdit->Text.Length(); x++)
13194  {
13195  if((YardEdit->Text[x] < '0') || (YardEdit->Text[x] > '9'))
13196  {
13197  MetreVariableLabel->Caption = "Entry error";
13198  ErrorFlag = true;
13199  break;
13200  }
13201  }
13202  }
13203  if((MileEdit->Text.Length() > 5) || (ChainEdit->Text.Length() > 5) || (YardEdit->Text.Length() > 5))
13204  {
13205  TooLongFlag = true;
13206  MetreVariableLabel->Caption = "Too big";
13207  }
13208  if(!ErrorFlag && !TooLongFlag)
13209  {
13210  int Miles = 0, Chains = 0, Yards = 0, Metres = 0;
13211  if(MileEdit->Text.Length() > 0)
13212  {
13213  Miles = MileEdit->Text.ToInt();
13214  }
13215  if(ChainEdit->Text.Length() > 0)
13216  {
13217  Chains = ChainEdit->Text.ToInt();
13218  }
13219  if(YardEdit->Text.Length() > 0)
13220  {
13221  Yards = YardEdit->Text.ToInt();
13222  }
13223  Metres = int((Miles * 1609.344) + (Chains * 20.1168) + (Yards * 0.9144) + 0.5);
13224  MetreVariableLabel->Caption = AnsiString(Metres);
13225  }
13226  if((MileEdit->Text.Length() == 0) && (ChainEdit->Text.Length() == 0) && (YardEdit->Text.Length() == 0))
13227  {
13228  MetreVariableLabel->Caption = "";
13229  }
13230  Utilities->CallLogPop(1867);
13231  }
13232  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash //non-error catch
13233  {
13234  MetreVariableLabel->Caption = "Entry error";
13235  Utilities->CallLogPop(2310);
13236  }
13237  catch(const Exception &e)
13238  {
13239  ErrorLog(178, e.Message);
13240  }
13241 }
13242 
13243 // ---------------------------------------------------------------------------
13244 
13245 void __fastcall TInterface::TTClockAdjButtonClick(TObject *Sender)
13246 {
13247  try
13248  {
13249  TrainController->LogEvent("TTClockAdjButtonClick");
13250  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdjButtonClick");
13251 // Utilities->Clock2Stopped = true; // to keep panel buttons disabled, restarted on exit
13252  Display->HideWarningLog(0); // because this panel overwrites it
13253  TTClockAdjPanel->Visible = true;
13254  TTClockAdjButton->Enabled = false;
13255 /*
13256  OperatingPanelLabel->Caption = "Disabled"; all these now dealt with in ClockTimer2
13257  OperatingPanel->Enabled = false;
13258  ZoomButton->Enabled = false;
13259  HomeButton->Enabled = false;
13260  NewHomeButton->Enabled = false;
13261  ScreenLeftButton->Enabled = false;
13262  ScreenRightButton->Enabled = false;
13263  ScreenUpButton->Enabled = false;
13264  ScreenDownButton->Enabled = false;
13265 */
13266  Utilities->CallLogPop(1875);
13267  }
13268  catch(const Exception &e)
13269  {
13270  ErrorLog(181, e.Message);
13271  }
13272 }
13273 
13274 // ---------------------------------------------------------------------------
13275 
13276 void __fastcall TInterface::TTClockExitButtonClick(TObject *Sender)
13277 {
13278  try
13279  {
13280  TrainController->LogEvent("TTClockExitButtonClick");
13281  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockExitButtonClick");
13282  TTClockAdjPanel->Visible = false;
13283  TTClockAdjButton->Enabled = true;
13284 /* these dealt with in ClockTimer2
13285  ZoomButton->Enabled = true;
13286  HomeButton->Enabled = true;
13287  NewHomeButton->Enabled = true;
13288  ScreenLeftButton->Enabled = true;
13289  ScreenRightButton->Enabled = true;
13290  ScreenUpButton->Enabled = true;
13291  ScreenDownButton->Enabled = true;
13292  OperatingPanel->Enabled = true;
13293  OperatingPanelLabel->Caption = "Operation";
13294 */
13295  Display->ShowWarningLog(0);
13296  double TTClockTimeChange = double(TrainController->RestartTime) - PauseEntryRestartTime;
13297  if((TTClockSpeed != PauseEntryTTClockSpeed) || (TTClockTimeChange > 0.000347))
13298  {
13299  // 30 seconds, min increase is 1 minute & don't trust doubles to stay exactly equal
13301  {
13302  TTClockAdjustWarningPanel->Top = MainScreen->Top + ((MainScreen->Height - TTClockAdjustWarningPanel->Height) / 2);
13303  TTClockAdjustWarningPanel->Left = MainScreen->Left + ((MainScreen->Width - TTClockAdjustWarningPanel->Width) / 2);
13304  TTClockAdjustWarningLabel->Caption =
13305  "Changes have been made to the timetable clock - you may wish to save a session before resuming operation.\n\nTo cancel all changes re-click the 'Adjust the timetable clock' button then click the reset button BEFORE resuming operation.";
13306  TTClockAdjustWarningPanel->Visible = true;
13307  }
13308  }
13309 // Utilities->Clock2Stopped = false; // as above
13311 // to restore the ability to reselect T after adj panel hidden (FormKeyUp doesn't work because the Interface form doesn't have focus)
13312  Utilities->CallLogPop(1876);
13313  }
13314  catch(const Exception &e)
13315  {
13316  ErrorLog(182, e.Message);
13317  }
13318 }
13319 // ---------------------------------------------------------------------------
13320 
13321 void __fastcall TInterface::TTClockx2ButtonClick(TObject *Sender)
13322 {
13323  try
13324  {
13325  TrainController->LogEvent("TTClockx2ButtonClick");
13326  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx2ButtonClick");
13327  TTClockSpeed = 2;
13328  TTClockSpeedLabel->Caption = "x2";
13330  Utilities->CallLogPop(1878);
13331  }
13332  catch(const Exception &e)
13333  {
13334  ErrorLog(184, e.Message);
13335  }
13336 }
13337 
13338 // ---------------------------------------------------------------------------
13339 
13340 void __fastcall TInterface::TTClockx4ButtonClick(TObject *Sender)
13341 {
13342  try
13343  {
13344  TrainController->LogEvent("TTClockx4ButtonClick");
13345  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx4ButtonClick");
13346  TTClockSpeed = 4;
13347  TTClockSpeedLabel->Caption = "x4";
13349  Utilities->CallLogPop(1883);
13350  }
13351  catch(const Exception &e)
13352  {
13353  ErrorLog(189, e.Message);
13354  }
13355 }
13356 
13357 // ---------------------------------------------------------------------------
13358 
13359 void __fastcall TInterface::TTClockx8ButtonClick(TObject *Sender)
13360 {
13361  try
13362  {
13363  TrainController->LogEvent("TTClockx8ButtonClick");
13364  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx8ButtonClick");
13365  TTClockSpeed = 8;
13366  TTClockSpeedLabel->Caption = "x8";
13368  Utilities->CallLogPop(1884);
13369  }
13370  catch(const Exception &e)
13371  {
13372  ErrorLog(190, e.Message);
13373  }
13374 }
13375 
13376 // ---------------------------------------------------------------------------
13377 
13378 void __fastcall TInterface::TTClockx16ButtonClick(TObject *Sender)
13379 {
13380  try
13381  {
13382  TrainController->LogEvent("TTClockx16ButtonClick");
13383  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx16ButtonClick");
13384  TTClockSpeed = 16;
13385  TTClockSpeedLabel->Caption = "x16";
13387  Utilities->CallLogPop(1885);
13388  }
13389  catch(const Exception &e)
13390  {
13391  ErrorLog(191, e.Message);
13392  }
13393 }
13394 
13395 // ---------------------------------------------------------------------------
13396 
13397 void __fastcall TInterface::TTClockx1ButtonClick(TObject *Sender)
13398 {
13399  try
13400  {
13401  TrainController->LogEvent("TTClockx1ButtonClick");
13402  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx1ButtonClick");
13403  TTClockSpeed = 1;
13404  TTClockSpeedLabel->Caption = "x1";
13406  Utilities->CallLogPop(1886);
13407  }
13408  catch(const Exception &e)
13409  {
13410  ErrorLog(192, e.Message);
13411  }
13412 }
13413 
13414 // ---------------------------------------------------------------------------
13415 
13416 void __fastcall TInterface::TTClockxHalfButtonClick(TObject *Sender)
13417 {
13418  try
13419  {
13420  TrainController->LogEvent("TTClockxHalfButtonClick");
13421  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxHalfButtonClick");
13422  TTClockSpeed = 0.5;
13423  TTClockSpeedLabel->Caption = "x1/2";
13425  Utilities->CallLogPop(1887);
13426  }
13427  catch(const Exception &e)
13428  {
13429  ErrorLog(193, e.Message);
13430  }
13431 }
13432 
13433 // ---------------------------------------------------------------------------
13434 
13435 void __fastcall TInterface::TTClockxQuarterButtonClick(TObject *Sender)
13436 {
13437  try
13438  {
13439  TrainController->LogEvent("TTClockxQuarterButtonClick");
13440  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxQuarterButtonClick");
13441  TTClockSpeed = 0.25;
13442  TTClockSpeedLabel->Caption = "x1/4";
13444  Utilities->CallLogPop(1888);
13445  }
13446  catch(const Exception &e)
13447  {
13448  ErrorLog(194, e.Message);
13449  }
13450 }
13451 
13452 // ---------------------------------------------------------------------------
13453 
13454 void __fastcall TInterface::TTClockxEighthButtonClick(TObject *Sender)
13455 {
13456  // added for v2.3.0 for very big railways
13457  try
13458  {
13459  TrainController->LogEvent("TTClockxEighthButtonClick");
13460  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxEighthButtonClick");
13461  TTClockSpeed = 0.125;
13462  TTClockSpeedLabel->Caption = "x1/8";
13464  Utilities->CallLogPop(2099);
13465  }
13466  catch(const Exception &e)
13467  {
13468  ErrorLog(203, e.Message);
13469  }
13470 }
13471 // ---------------------------------------------------------------------------
13472 
13473 void __fastcall TInterface::TTClockxSixteenthButtonClick(TObject *Sender)
13474 {
13475  // added for v2.3.0 for very big railways
13476  try
13477  {
13478  TrainController->LogEvent("TTClockxSixteenthButtonClick");
13479  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxSixteenthButtonClick");
13480  TTClockSpeed = 0.0625;
13481  TTClockSpeedLabel->Caption = "x1/16";
13483  Utilities->CallLogPop(2100);
13484  }
13485  catch(const Exception &e)
13486  {
13487  ErrorLog(204, e.Message);
13488  }
13489 }
13490 
13491 // ---------------------------------------------------------------------------
13492 
13493 void __fastcall TInterface::TTClockAdd1hButtonClick(TObject *Sender)
13494 {
13495  try
13496  {
13497  TrainController->LogEvent("TTClockAdd1hButtonClick");
13498  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd1hButtonClick");
13499  double TTClockIncrement = 1.0 / 24;
13500  TrainController->RestartTime += TDateTime(TTClockIncrement);
13503  Utilities->CallLogPop(1879);
13504  }
13505  catch(const Exception &e)
13506  {
13507  ErrorLog(185, e.Message);
13508  }
13509 }
13510 
13511 // ---------------------------------------------------------------------------
13512 
13513 void __fastcall TInterface::TTClockAdd10mButtonClick(TObject *Sender)
13514 {
13515  try
13516  {
13517  TrainController->LogEvent("TTClockAdd10mButtonClick");
13518  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd10mButtonClick");
13519  double TTClockIncrement = 1.0 / 144;
13520  TrainController->RestartTime += TDateTime(TTClockIncrement);
13523  Utilities->CallLogPop(1881);
13524  }
13525  catch(const Exception &e)
13526  {
13527  ErrorLog(187, e.Message);
13528  }
13529 }
13530 
13531 // ---------------------------------------------------------------------------
13532 
13533 void __fastcall TInterface::TTClockAdd1mButtonClick(TObject *Sender)
13534 {
13535  try
13536  {
13537  TrainController->LogEvent("TTClockAdd1mButtonClick");
13538  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd1mButtonClick");
13539  double TTClockIncrement = 1.0 / 1440;
13540  TrainController->RestartTime += TDateTime(TTClockIncrement);
13543  Utilities->CallLogPop(1882);
13544  }
13545  catch(const Exception &e)
13546  {
13547  ErrorLog(188, e.Message);
13548  }
13549 }
13550 
13551 // ---------------------------------------------------------------------------
13552 
13553 void __fastcall TInterface::TTClockResetButtonClick(TObject *Sender)
13554 {
13555  try
13556  {
13557  TrainController->LogEvent("TTClockResetButtonClick");
13558  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockResetButtonClick");
13563  if(TTClockSpeed == 2)
13564  {
13565  TTClockSpeedLabel->Caption = "x2";
13566  }
13567  else if(TTClockSpeed == 4)
13568  {
13569  TTClockSpeedLabel->Caption = "x4";
13570  }
13571  else if(TTClockSpeed == 8)
13572  {
13573  TTClockSpeedLabel->Caption = "x8";
13574  }
13575  else if(TTClockSpeed == 16)
13576  {
13577  TTClockSpeedLabel->Caption = "x16";
13578  }
13579  else if(TTClockSpeed == 0.5)
13580  {
13581  TTClockSpeedLabel->Caption = "x1/2";
13582  }
13583  else if(TTClockSpeed == 0.25)
13584  {
13585  TTClockSpeedLabel->Caption = "x1/4";
13586  }
13587  else if(TTClockSpeed == 0.125)
13588  {
13589  TTClockSpeedLabel->Caption = "x1/8";
13590  }
13591  else if(TTClockSpeed == 0.0625)
13592  {
13593  TTClockSpeedLabel->Caption = "x1/16";
13594  }
13595  else
13596  {
13597  TTClockSpeed = 1;
13598  TTClockSpeedLabel->Caption = "x1";
13599  }
13600  Utilities->CallLogPop(1880);
13601  }
13602  catch(const Exception &e)
13603  {
13604  ErrorLog(186, e.Message);
13605  }
13606 }
13607 
13608 // ---------------------------------------------------------------------------
13609 
13610 void __fastcall TInterface::PresetAutoSigRoutesButtonClick(TObject *Sender)
13611 {
13612  try
13613  {
13614  TrainController->LogEvent("PresetAutoSigRoutesButtonClick");
13615  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PresetAutoSigRoutesButtonClick");
13616  InfoPanel->Caption = "PRE-START: Presetting automatic signal routes";
13617  OperatingPanelLabel->Caption = "Disabled";
13618  OperatingPanel->Enabled = false; // becomes re-enabled during the call to ClockTimer2
13619  ZoomButton->Enabled = false;
13620  HomeButton->Enabled = false;
13621  NewHomeButton->Enabled = false;
13622  ScreenLeftButton->Enabled = false;
13623  ScreenRightButton->Enabled = false;
13624  ScreenUpButton->Enabled = false;
13625  ScreenDownButton->Enabled = false;
13626 
13627  Screen->Cursor = TCursor(-11); // Hourglass
13628  TPrefDirElement StartElement, EndElement;
13629  bool PointsChanged, AtLeastOneSet = false;
13630  int LastIteratorValue = 0;
13631  while(true)
13632  {
13633  if(!EveryPrefDir->GetStartAndEndPrefDirElements(0, StartElement, EndElement, LastIteratorValue))
13634  {
13635  break;
13636  }
13637  // rest of routine here - i.e. build the routes
13638  ConstructRoute->ClearRoute(); // in case not empty though should be
13639  AtLeastOneSet = true;
13640  if(ConstructRoute->GetPreferredRouteStartElement(1, StartElement.HLoc, StartElement.VLoc, EveryPrefDir, true)) // true for AutoSigsFlag
13641  {
13642  }
13643  if(ConstructRoute->GetNextPreferredRouteElement(1, EndElement.HLoc, EndElement.VLoc, EveryPrefDir, true, true, ConstructRoute->ReqPosRouteID,
13644  PointsChanged))
13645  {
13646  }
13648  }
13649  if(AtLeastOneSet)
13650  {
13653  }
13654  else
13655  {
13656  ShowMessage("No presettable automatic signal routes are available");
13657  }
13658  Screen->Cursor = TCursor(-2); // Arrow
13659  Utilities->CallLogPop(1994);
13660  }
13661  catch(const Exception &e)
13662  {
13663  ErrorLog(195, e.Message);
13664  }
13665 }
13666 
13667 // ---------------------------------------------------------------------------
13668 
13669 void __fastcall TInterface::FormResize(TObject *Sender) // new at v2.1.0
13670 {
13671  try
13672  {
13673  if(!SkipFormResizeEvent) // to avoid calling during startup and especially during shutdown
13674  {
13675  // else fails on shutdown because HiddenScreen & other things no longer exist
13676  int DispW = (Interface->Width - 64 - 16) / 16;
13677 // will truncate down to a multiple of 16 (64 = side panels and 16 compensates for excess width of Interface)
13678  int DispH = (Interface->Height - 192) / 16;
13679  MainScreen->Width = DispW * 16;
13680  MainScreen->Height = DispH * 16;
13681  Utilities->ScreenElementWidth = DispW;
13682  Utilities->ScreenElementHeight = DispH;
13683  HiddenScreen->Width = MainScreen->Width;
13684  HiddenScreen->Height = MainScreen->Height;
13685  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
13686  PerformancePanel->Left = MainScreen->Left;
13687  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height; // new at v2.2.0
13688  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width;
13689  SigImagePanel->Left = (Interface->Width - SigImagePanel->Width) / 2; // added for v2.3.0
13690  DevelopmentPanel->Top = MainScreen->Top + MainScreen->Height - DevelopmentPanel->Height; // new v2.2.0
13691  DevelopmentPanel->Left = MainScreen->Left + MainScreen->Width - DevelopmentPanel->Width; // new v2.2.0
13692  MTBFEditBox->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 32; // new v2.4.0 32 is to place it above the positional panel
13693  MTBFLabel->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30 - 55; // new v2.4.0 placed above and to the left of MTBFEditBox
13694  PositionalPanel->Left = MainScreen->Left + MainScreen->Width; // changed at v2.4.0
13695  PositionalPanel->Top = MainScreen->Top; // changed at v2.4.0
13696  PositionalPanel->Height = MainScreen->Height; // changed at v2.4.0
13697 
13698  if(!Display->ZoomOutFlag)
13699  {
13701  }
13702  else
13703  {
13704  Display->ClearDisplay(11);
13706  }
13707  Display->Update();
13708  }
13709  }
13710  catch(const Exception &e)
13711  {
13712  ErrorLog(197, e.Message);
13713  }
13714 }
13715 
13716 // ---------------------------------------------------------------------------
13717 
13718 void __fastcall TInterface::OperatorActionButtonClick(TObject *Sender)
13719 {
13720  try
13721  {
13722  TrainController->LogEvent("OperatorActionButtonClick");
13723  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperatorActionButtonClick");
13725  {
13726  ShowOperatorActionPanel = true;
13727  OperatorActionPanel->Visible = true;
13729  OperatorActionButton->Glyph->LoadFromResourceName(0, "HideOpActionPanel");
13730  }
13731  else
13732  {
13733  ShowOperatorActionPanel = false;
13734  OperatorActionPanel->Visible = false;
13736  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel");
13737  }
13738  Utilities->CallLogPop(2073);
13739  }
13740  catch(const Exception &e)
13741  {
13742  ErrorLog(199, e.Message);
13743  }
13744 }
13745 
13746 // ---------------------------------------------------------------------------
13747 
13748 void __fastcall TInterface::ConverttoRightHandSignalsMenuItemClick(TObject *Sender)
13749 {
13750  try
13751  {
13752  TrainController->LogEvent("ConverttoRightHandSignalsMenuItemClick");
13753  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ConverttoRightHandSignalsMenuItemClick");
13755  if(Utilities->RHSignalFlag) // RH sigs after conversion
13756  {
13757  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Left Hand Signals";
13759  {
13761  }
13762  else
13763  {
13765  }
13766  SigImagePanel->Caption = "Signals will be on the right hand side of the track";
13767  SigsOnLeftImage1->Visible = false;
13768  SigsOnLeftImage2->Visible = false;
13769  SigsOnRightImage1->Visible = true;
13770  SigsOnRightImage2->Visible = true;
13771  std::ofstream SigFile((CurDir + "\\Signal.hnd").c_str());
13772  if(SigFile.fail())
13773  {
13774  ShowMessage("Failed to store right hand signal setting, program will default to left hand signals when next loaded");
13775  }
13776  else
13777  {
13778  Utilities->SaveFileString(SigFile, "RHSignals");
13779  }
13780  }
13781  else // LH sigs after conversion
13782  {
13783  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
13785  {
13787  }
13788  else
13789  {
13791  }
13792  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
13793  SigsOnRightImage1->Visible = false;
13794  SigsOnRightImage2->Visible = false;
13795  SigsOnLeftImage1->Visible = true;
13796  SigsOnLeftImage2->Visible = true;
13797  std::ofstream SigFile((CurDir + "\\Signal.hnd").c_str());
13798  if(SigFile.fail())
13799  {
13800  // no need for message as will default to LH: ShowMessage("Failed to store left hand signal setting, program will default to left hand signals when next loaded");
13801  }
13802  else
13803  {
13804  Utilities->SaveFileString(SigFile, "LHSignals");
13805  }
13806  }
13807  Utilities->CallLogPop(2097);
13808  }
13809  catch(const Exception &e)
13810  {
13811  ErrorLog(202, e.Message);
13812  }
13813 }
13814 // ---------------------------------------------------------------------------
13815 
13816 void __fastcall TInterface::MTBFEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
13817 
13818 {
13819  try
13820  {
13821  TrainController->LogEvent("MTBFEditBoxKeyUp," + AnsiString(Key));
13822  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxKeyUp," + AnsiString(Key));
13823  if((Level1Mode != OperMode) || (Level2OperMode != PreStart))
13824  {
13825  Utilities->CallLogPop(2160);
13826  return;
13827  }
13828  bool TooBigFlag = false, BadCharsFlag = false;
13831  if(MTBFEditBox->Text.Length() > 0)
13832  {
13833  for(int x = 1; x <= MTBFEditBox->Text.Length(); x++)
13834  {
13835  if((MTBFEditBox->Text[x] < '0') || (MTBFEditBox->Text[x] > '9'))
13836  {
13837  BadCharsFlag = true;
13838  break;
13839  }
13840  }
13841  if(!BadCharsFlag)
13842  {
13843  if(StrToInt(MTBFEditBox->Text) > 10000)
13844  {
13845  TooBigFlag = true;
13846  }
13847  }
13848  if(TooBigFlag)
13849  {
13850  ShowMessage("Maximum value allowed is 9,999");
13851  MTBFEditBox->Text = "";
13854  Utilities->CallLogPop(2161);
13855  return;
13856  }
13857  if(BadCharsFlag)
13858  {
13859  ShowMessage("Value must be a whole number with no special characters");
13860  MTBFEditBox->Text = "";
13863  Utilities->CallLogPop(2162);
13864  return;
13865  }
13866  TrainController->AvHoursIntValue = StrToInt(MTBFEditBox->Text); // ok if user enters 0 as that means no failures
13868  }
13870  {
13871  MTBFEditBox->Text = "";
13873  }
13874  Utilities->CallLogPop(2163);
13875  }
13876  catch(const Exception &e)
13877  {
13878  ErrorLog(209, e.Message);
13879  }
13880 }
13881 
13882 // ---------------------------------------------------------------------------
13883 
13884 void __fastcall TInterface::MTBFEditBoxClick(TObject *Sender)
13885 {
13886  try
13887  {
13888  TrainController->LogEvent("MTBFEditBoxClick");
13889  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxClick");
13890  if((Level1Mode != OperMode) || (Level2OperMode != PreStart))
13891  {
13892  MTBFEditBox->ReadOnly = true; // it should be anyway but include here for safety
13894  "Values can only be entered or changed in Pre-Start mode\ni.e. after selecting 'Operate railway' but before clicking 'Run'");
13895  }
13896  Utilities->CallLogPop(2164);
13897  }
13898  catch(const Exception &e)
13899  {
13900  ErrorLog(210, e.Message);
13901  }
13902 }
13903 
13904 // ---------------------------------------------------------------------------
13905 
13906 void __fastcall TInterface::UserGraphicButtonClick(TObject *Sender)
13907 {
13908  try
13909  {
13910  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxClick");
13911  LengthConversionPanel->Visible = false;
13912  SpeedConversionPanel->Visible = false;
13913  DistanceKey->Visible = false;
13914  TrackElementPanel->Visible = false;
13915  SigAspectButton->Enabled = false;
13917  SetLevel2TrackMode(63);
13918  Display->Update();
13919  if((SelectedGraphicFileName != "") && (!Track->UserGraphicVector.empty()))
13920  // latter condition added at v2.6.0 because showed after ClearAll & reselect failed
13921  {
13922  UserGraphicReselectPanel->Visible = true;
13923  }
13924  else
13925  {
13926  UserGraphicReselectPanel->Visible = false;
13927  LoadUserGraphic(0);
13928  }
13929  Utilities->CallLogPop(2183);
13930  }
13931  catch(const Exception &e)
13932  {
13933  ErrorLog(212, e.Message);
13934  }
13935 }
13936 
13937 // ---------------------------------------------------------------------------
13938 
13939 void __fastcall TInterface::ReselectUserGraphicClick(TObject *Sender)
13940 {
13941  try
13942  {
13943  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ReselectUserGraphicClick");
13944  TrainController->LogEvent("ReselectUserGraphicClick " + SelectedGraphicFileName);
13945  UserGraphicReselectPanel->Visible = false;
13946  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
13947  if(UGMIt == Track->UserGraphicMap.end())
13948  {
13949  ShowMessage("Unable to find graphic file " + SelectedGraphicFileName + ". Check it still exists.");
13950  Utilities->CallLogPop(2196);
13951  return;
13952  }
13954  SetLevel2TrackMode(64);
13955  Utilities->CallLogPop(2184);
13956  }
13957  catch(const Exception &e)
13958  {
13959  ErrorLog(213, e.Message);
13960  }
13961 }
13962 // ---------------------------------------------------------------------------
13963 
13964 void __fastcall TInterface::SelectNewGraphicClick(TObject *Sender)
13965 {
13966  try
13967  {
13968  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectNewGraphicClick");
13969  UserGraphicReselectPanel->Visible = false;
13970  LoadUserGraphic(1);
13971  Utilities->CallLogPop(2185);
13972  }
13973  catch(const Exception &e)
13974  {
13975  ErrorLog(214, e.Message);
13976  }
13977 }
13978 
13979 // ---------------------------------------------------------------------------
13980 
13981 void __fastcall TInterface::TTClockAdjustOKButtonClick(TObject *Sender)
13982 {
13983  try
13984  {
13985  TrainController->LogEvent("TTClockAdjustOKButtonClick");
13986  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdjustOKButtonClick");
13987  TTClockAdjustWarningPanel->Visible = false;
13988  if(TTClockAdjustCheckBox->Checked)
13989  {
13990  TTClockAdjustWarningHide = true;
13991  }
13992  Utilities->CallLogPop(2219);
13993  }
13994  catch(const Exception &e)
13995  {
13996  ErrorLog(216, e.Message);
13997  }
13998 }
13999 
14000 // ---------------------------------------------------------------------------
14001 
14002 void __fastcall TInterface::TwoLocationNameButtonClick(TObject *Sender)
14003 {
14004  try
14005  {
14006  TrainController->LogEvent("TwoLocationNameButtonClick");
14007  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TwoLocationNameButtonClick");
14008  TwoLocationNamePanel->Visible = false;
14009  ShowHideTTButton->Enabled = true;
14010  ExitTTModeButton->Enabled = true;
14011  TimetableEditPanel->Enabled = true;
14012  if(TwoLocationNameCheckBox->Checked)
14013  {
14014  TwoLocationNamePanelHide = true;
14015  }
14016  Utilities->CallLogPop(2316);
14017  }
14018  catch(const Exception &e)
14019  {
14020  ErrorLog(224, e.Message);
14021  }
14022 }
14023 
14024 //---------------------------------------------------------------------------
14025 
14026 void __fastcall TInterface::ConflictAnalysisButtonClick(TObject *Sender)
14027 {
14028  try
14029  {
14030  TrainController->LogEvent("ConflictAnalysisButtonClick");
14031  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ConflictAnalysisButtonClick");
14032  ConflictPanel->Visible = true;
14033  Utilities->CallLogPop(2220);
14034  }
14035  catch(const Exception &e)
14036  {
14037  ErrorLog(217, e.Message);
14038  }
14039 }
14040 
14041 // ---------------------------------------------------------------------------
14042 
14043 void __fastcall TInterface::CPCancelButtonClick(TObject *Sender)
14044 {
14045  try
14046  {
14047  TrainController->LogEvent("CPCancelButtonClick");
14048  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CPCancelButtonClick");
14049  ConflictPanel->Visible = false;
14050  Utilities->CallLogPop(2221);
14051  }
14052  catch(const Exception &e)
14053  {
14054  ErrorLog(218, e.Message);
14055  }
14056 }
14057 
14058 // ---------------------------------------------------------------------------
14059 
14060 void __fastcall TInterface::CPGenFileButtonClick(TObject *Sender)
14061 {
14062  try
14063  {
14064  TrainController->LogEvent("CPGenFileButtonClick");
14065  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CPGenFileButtonClick");
14066  if(!CPArrivalsCheckBox->Checked && !CPDeparturesCheckBox->Checked && !CPAtLocCheckBox->Checked && !CPDirectionsCheckBox->Checked)
14067  {
14068  ShowMessage("No boxes ticked!");
14069  }
14070  else // keep ticks & range values from last time, only reset on startup
14071  {
14072  Screen->Cursor = TCursor(-11); // hourglass
14073  AnsiString TTTitle;
14075  {
14076  for(int x = CreateEditTTFileName.Length(); x > 0; x--) // first need to strip out the timetable title from the full name
14077  {
14078  if(CreateEditTTFileName[x] == '\\')
14079  {
14080  TTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
14081  break;
14082  }
14083  }
14085  CPAtLocCheckBox->Checked, CPDirectionsCheckBox->Checked, CPEditArrRange->Text.ToInt(), CPEditDepRange->Text.ToInt()))
14086  {
14087  ShowMessage("Analysis complete and file created");
14088  }
14089  ConflictPanel->Visible = false;
14090  }
14091  }
14092  Screen->Cursor = TCursor(-2); // arrow
14093  Utilities->CallLogPop(2222);
14094  }
14095  catch(const Exception &e)
14096  {
14097  ErrorLog(219, e.Message);
14098  }
14099 }
14100 
14101 // ---------------------------------------------------------------------------
14102 // end of fastcalls & directly associated functions
14103 // ---------------------------------------------------------------------------
14104 
14105 void TInterface::SetTopIndex(int Caller)
14106 {
14107 // Set TopIndex to the proper value & also Selected so don't have a different selection to the highlighted entry
14108  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTopIndex");
14109  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < AllEntriesTTListBox->TopIndex)
14110  {
14112  }
14113  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (AllEntriesTTListBox->TopIndex + 45))
14114  {
14115  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
14116  }
14117  else
14118  {
14119  AllEntriesTTListBox->TopIndex = AllEntriesTTListBox->TopIndex;
14120  }
14121  AllEntriesTTListBox->Selected[TTCurrentEntryPtr - TimetableEditVector.begin()] = true;
14122  Utilities->CallLogPop(2207);
14123 }
14124 
14125 // ---------------------------------------------------------------------------
14126 
14127 void TInterface::ClearandRebuildRailway(int Caller) // now uses HiddenScreen to help avoid flicker
14128 {
14129  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearandRebuildRailway");
14130  bool ClockState = Utilities->Clock2Stopped;
14131 
14132  Utilities->Clock2Stopped = true;
14134  Track->RebuildUserGraphics(0, HiddenDisplay); // new at v2.4.0, plot first so all else overwrites, including the grid if selected
14135  if(ScreenGridFlag && (Level1Mode == TrackMode))
14136  {
14137  int WidthNum = int(MainScreen->Width / 160) + 1;
14138  int HeightNum = int(MainScreen->Height / 144) + 1;
14139  for(int x = 0; x < WidthNum; x++)
14140  {
14141  for(int y = 0; y < HeightNum; y++)
14142  {
14143  HiddenDisplay->PlotAbsolute(0, x * 160, y * 144, RailGraphics->GridBitmap);
14144  }
14145  }
14146  }
14147 // TextHandler->RebuildFromTextVector(1, HiddenDisplay); //This now incorporated in RebuildTrackAndText so that text is plotted after inactive
14148 // elements but before active elements. This is so text can overwite stations and non-station named locations.
14149 
14151 
14152 // Display->Output->Invalidate(); experiment, needs TDisplay Output to be public. Trying to invoke the white flashes that
14153 // used to occur frequently without Disp->Update() in PlotOriginal
14154 
14155  // OperMode LCs plotted below
14157  {
14159  }
14160  if(Level1Mode == PrefDirMode)
14161  {
14162  if(EveryPrefDir->PrefDirSize() > 0)
14163  {
14165  }
14167  {
14169  }
14170  }
14171  if(Level1Mode == TrackMode)
14172  {
14174  {
14175  LocationNameButton->Enabled = true;
14176  }
14177  else
14178  {
14179  LocationNameButton->Enabled = false;
14180  }
14181  }
14183  {
14185  DistanceKey->Visible = true;
14186  DistancesMarked = true;
14187  LengthConversionPanel->Visible = true;
14188  SpeedConversionPanel->Visible = true;
14189  }
14190  if(Level2TrackMode == DistanceContinuing) // for extended distances
14191  {
14192  if(ConstructPrefDir->PrefDirSize() > 0)
14193  {
14195 // this line was after the next line until v2.5.1, changed so magenta not overrridden after PrefDirMarker called
14197  DistanceKey->Visible = true;
14198  DistancesMarked = true;
14199  LengthConversionPanel->Visible = true;
14200  SpeedConversionPanel->Visible = true;
14201  }
14202  }
14204  // this is to keep the distance markers if they are already present when Select is chosen, in case user wishes to choose SelectLengths,
14205  // don't need to display ConstructPrefDir marker as that only needed in DistanceContinuing mode
14206  {
14208  DistanceKey->Visible = true;
14209  }
14211  // cancel DistancesMarked if exit from any of these modes
14212  {
14213  DistancesMarked = false;
14214  DistanceKey->Visible = false;
14215  LengthConversionPanel->Visible = false; // added at v1.3.1 to remove when distance/speed setting exited
14216  SpeedConversionPanel->Visible = false; // added at v1.3.1 to remove when distance/speed setting exited
14217  }
14219  // in process of moving so use NewSelectBitmapHLoc & VLoc
14220  {
14222  }
14223 
14225  // not in process of moving or failed to click mouse within selection so use SelectBitmapHLoc & VLoc
14226  {
14228  }
14229  if(Level1Mode == OperMode)
14230  {
14232  if(!AllRoutes->LockedRouteVector.empty())
14233  {
14234  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
14235  {
14236  if(!(AllRoutes->TrackIsInARoute(7, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos)))
14237  {
14238  AllRoutes->LockedRouteVector.erase(LRVIT);
14239  // if end element not in route then a train must have entered it from the wrong end and erased the whole route,
14240  // hence no longer needed so get rid of it (end of route can't be points, crossover or bridge so danger of
14241  // route being on the other track of a 2-track element doesn't arise)
14242  continue;
14243  }
14244  TOneRoute Route = AllRoutes->GetFixedRouteAt(0, LRVIT->RouteNumber);
14245  int x = Route.PrefDirSize() - 1;
14246  bool BreakFlag = false;
14247  TPrefDirElement PrefDirElement = Route.GetFixedPrefDirElementAt(1, x);
14248  while(PrefDirElement.GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
14249  {
14250  HiddenDisplay->PlotOutput(10, (PrefDirElement.HLoc) * 16, (PrefDirElement.VLoc) * 16,
14251  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
14252  if(!(AllRoutes->TrackIsInARoute(8, PrefDirElement.Conn[PrefDirElement.GetELinkPos()],
14253  PrefDirElement.ConnLinkPos[PrefDirElement.GetELinkPos()])))
14254  {
14255  BreakFlag = true;
14256  break; // train removed earlier element from route so stop here
14257  }
14258  x--;
14259  if(x < 0) // added after Albie Vowles reported error on 14/08/20 by email
14260  {
14261  // it means that part of the route (including that at the truncate point) has been cancelled, in this case by a train running past the signal
14262  BreakFlag = true;
14263 // at danger and cancelling the route elements in front of it. The locked route is now too short and this 'while' loop won't find
14264  break; // it, so x keeps decrementing and when it becomes -1 an error is thrown. This addition prevents the error.
14265  }
14266  PrefDirElement = Route.GetFixedPrefDirElementAt(2, x);
14267  }
14268  if(!BreakFlag)
14269  {
14270  if(PrefDirElement.GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
14271  {
14272  HiddenDisplay->PlotOutput(11, (PrefDirElement.HLoc) * 16, (PrefDirElement.VLoc) * 16,
14273  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
14274  }
14275  }
14276  }
14277  }
14278  if(RouteMode == RouteContinuing)
14279  {
14281 // system thinks overlay is already plotted, so plot original to reset the OverlayPlotted flag
14284  if(AutoSigsFlag)
14285  {
14287  }
14288  else if(PreferredRoute) // added at v2.7.0, was ConsecSignalsRoute
14289  {
14291  }
14292  else
14293  {
14295  }
14296  }
14297  if(Track->PointFlashFlag)
14298  {
14299  // need to reset the screen location for picking up the original graphic
14300  int Left, Top; // Embarcadero change - these missing in error from Borland file
14302  // note that the above Pos values are wrt layout, not the screen, but the Left & Top values are wrt screen
14303  PointFlash->SetSourceRect(Left, Top);
14304  PointFlash->LoadOriginalScreenGraphic(4); // reload from new position
14305  // doesn't matter whether Flash was on or off when this function called as will sort itself out later (may miss a flash but won't be noticeable)
14306  }
14307  // now plot level crossings (must be after routes). These don't need any base elements to be plotted as they are already plotted.
14308  // In order to avoid plotting the whole LC for every element of a LC a bool value - LCPlotted - is used to save time
14309  for(unsigned int x = 0; x < Track->LCVector.size(); x++)
14310  {
14311  (Track->InactiveTrackVector.begin() + (*(Track->LCVector.begin() + x)))->LCPlotted = false;
14312  }
14313  for(unsigned int x = 0; x < Track->LCVector.size(); x++)
14314  {
14315  int BaseSpeedTag;
14316  TTrackElement ATE;
14317  TTrackElement ITE = *(Track->InactiveTrackVector.begin() + (*(Track->LCVector.begin() + x)));
14318  {
14319  BaseSpeedTag = Track->GetTrackElementFromTrackMap(0, ITE.HLoc, ITE.VLoc).SpeedTag;
14320  if(ITE.LCPlotted == false)
14321  {
14322  if(ITE.Attribute == 0)
14323  {
14325  }
14326  else if(ITE.Attribute == 1)
14327  {
14328  // need to determine if should plot green (manual) or red (auto), but all linked LCs have ConsecSignals set to 2 in BarriersDownVector if manual
14329  // so just need to test this for the HLoc & VLoc position match
14330  for(unsigned int x = 0; x < Track->BarriersDownVector.size(); x++)
14331  {
14332  if((Track->BarriersDownVector.at(x).HLoc == ITE.HLoc) && (Track->BarriersDownVector.at(x).VLoc == ITE.VLoc))
14333  {
14334  if(Track->BarriersDownVector.at(x).TypeOfRoute == 2)
14335  {
14337  true); // true for manual = green
14338  }
14339  else
14340  {
14342  false); // false for auto = red
14343  }
14344  }
14345  }
14346  }
14347  // if ITE->Attribute == 2 then LC is changing, FlashingGraphics will take care of flashing & final plotting,
14348  // it won't set LCPlotted but no real time lost in this case
14349  }
14350  }
14351  }
14353  }
14354  Display->ZoomOutFlag = false;
14355  ZoomButton->Glyph->LoadFromResourceName(0, "ZoomOut");
14356  MainScreen->Picture->Bitmap->Assign(HiddenScreen->Picture->Bitmap);
14357  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
14358  Utilities->Clock2Stopped = ClockState;
14359  Utilities->CallLogPop(91);
14360 }
14361 
14362 // ---------------------------------------------------------------------------
14363 
14364 bool TInterface::HighLightOneGap(int Caller, int &HLoc, int &VLoc)
14365 {
14366  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",HighLightOneGap");
14367  if(Track->FindAndHighlightAnUnsetGap(1)) // true if find one
14368  {
14369  if(!PreventGapOffsetResetting) // don't reset display position if returning from zoomout mode
14370  {
14371  while((Display->DisplayOffsetH - Track->GetGapHLoc()) > 0)
14372  {
14373  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
14374  }
14376  {
14378  }
14379  while((Display->DisplayOffsetV - Track->GetGapVLoc()) > 0)
14380  {
14381  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
14382  }
14384  {
14386  }
14387  }
14388  InfoPanel->Visible = true;
14389  InfoPanel->Caption = "CONNECTING GAPS: Click on connecting element";
14390  ClearandRebuildRailway(31); // get rid of earlier gap selection
14391  Utilities->CallLogPop(92);
14392  return(true); // return as one now identified & over to MainScreenMouseDown with Level2TrackMode = GapSetting
14393  }
14394  Utilities->CallLogPop(93);
14395  return(false); // no unset ones left to find
14396 }
14397 
14398 // ---------------------------------------------------------------------------
14399 
14400 bool TInterface::ClearEverything(int Caller)
14401 {
14402  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearEverything");
14403  if(FileChangedFlag)
14404  {
14405  UnicodeString MessageStr = "The railway has changed, close it without saving?";
14406  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
14407  if(button == IDNO)
14408  {
14409  Utilities->CallLogPop(1140);
14410  return(false);
14411  }
14412  }
14413  Display->ClearDisplay(7);
14415 
14416  Display->DisplayOffsetH = 0;
14417  Display->DisplayOffsetV = 0;
14422 
14423 // these ensure that all persistent vectors, maps & multimaps etc are cleared
14424  delete TrainController;
14425  delete EveryPrefDir;
14426  delete SelectPrefDir;
14427  delete ConstructRoute;
14428  delete ConstructPrefDir;
14429  delete AllRoutes;
14430  delete Track;
14431  delete TextHandler;
14432 // NB can't delete & recreate Utilities or will lose the CallLog file & have errors due to log being empty when try to
14433 // pop earlier pushed values
14434 // OK though as no containers in Utilities that need to clear & PerformanceFile recreated when begin to operate a later
14435 // railway
14436  TextHandler = new TTextHandler;
14437  Track = new TTrack;
14438  AllRoutes = new TAllRoutes;
14440  ConstructRoute = new TOneRoute;
14441  EveryPrefDir = new TOnePrefDir;
14442  SelectPrefDir = new TOnePrefDir;
14444  PerformanceLogBox->Lines->Clear();
14445  ResetAll(1);
14446  Utilities->CallLogPop(94);
14447  return(true);
14448 }
14449 
14450 // ---------------------------------------------------------------------------
14451 
14452 bool TInterface::FileIntegrityCheck(int Caller, char *FileName) const // true for success
14453 {
14454  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FileIntegrityCheck," + AnsiString(FileName));
14455  std::ifstream VecFile(FileName);
14456 
14457  if(VecFile.is_open())
14458  {
14459  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // Program version
14460  {
14461  VecFile.close();
14462  Utilities->CallLogPop(1805);
14463  return(false);
14464  }
14465  if(!Utilities->CheckFileInt(VecFile, -1000000, 1000000)) // DisplayOffsetHHome
14466  {
14467  VecFile.close();
14468  Utilities->CallLogPop(1440);
14469  return(false);
14470  }
14471  if(!Utilities->CheckFileInt(VecFile, -1000000, 1000000)) // DisplayOffsetVHome
14472  {
14473  VecFile.close();
14474  Utilities->CallLogPop(1441);
14475  return(false);
14476  }
14477  bool GraphicsFollow = false;
14478  int NumberOfActiveElements;
14479  if(!(Track->CheckTrackElementsInFile(1, NumberOfActiveElements, GraphicsFollow, VecFile))) // for new loads
14480  {
14481  VecFile.close();
14482  Utilities->CallLogPop(95);
14483  return(false);
14484  }
14485  if(!(TextHandler->CheckTextElementsInFile(0, VecFile)))
14486  {
14487  VecFile.close();
14488  Utilities->CallLogPop(96);
14489  return(false);
14490  }
14491  if(!(EveryPrefDir->CheckOnePrefDir(0, NumberOfActiveElements, VecFile)))
14492  {
14493  VecFile.close();
14494  Utilities->CallLogPop(97);
14495  return(false);
14496  }
14497  if(GraphicsFollow)
14498  {
14499  if(!Track->CheckUserGraphics(0, VecFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
14500  {
14501  VecFile.close();
14502  Utilities->CallLogPop(2186);
14503  return(false);
14504  }
14505  }
14506  VecFile.close();
14507  }
14508  else
14509  {
14510  Utilities->CallLogPop(1153);
14511  return(false);
14512  }
14513  Utilities->CallLogPop(98);
14514  return(true);
14515 }
14516 
14517 // ---------------------------------------------------------------------------
14518 
14519 void TInterface::Delay(int Caller, double Msec)
14520 {
14521  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Delay," + AnsiString(Msec));
14522  TDateTime First, Second;
14523  bool Finished = false;
14524 
14525  First = TDateTime::CurrentDateTime();
14526  double TimeVal1 = 86400000 * double(First); // no of msec in a day
14527 
14528  while(!Finished)
14529  {
14530  Second = TDateTime::CurrentDateTime();
14531  double TimeVal2 = 86400000 * double(Second);
14532  if((TimeVal2 - TimeVal1) > Msec)
14533  {
14534  Finished = true;
14535  }
14536  }
14537  Utilities->CallLogPop(1203);
14538 }
14539 
14540 // ---------------------------------------------------------------------------
14541 
14542 void TInterface::ResetCurrentSpeedButton(int Caller)
14543 {
14544  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetCurrentSpeedButton");
14545  if(CurrentSpeedButton)
14546  {
14547  CurrentSpeedButton->Down = false;
14548  }
14549  CurrentSpeedButton = 0;
14550  Utilities->CallLogPop(1204);
14551 }
14552 
14553 // ---------------------------------------------------------------------------
14554 
14556 {
14557  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MovingTrainPresentOnFlashingRoute");
14558  int TrainID;
14559 
14560  if(ConstructRoute->SearchVectorSize() == 0)
14561  {
14562  Utilities->CallLogPop(99);
14563  return(false);
14564  }
14565  for(unsigned int x = 0; x < ConstructRoute->SearchVectorSize(); x++)
14566  {
14567  TPrefDirElement PrefDirElement = ConstructRoute->GetFixedSearchElementAt(14, x);
14568  if(PrefDirElement.TrackType == Bridge)
14569  {
14570  if(PrefDirElement.GetXLinkPos() < 2)
14571  {
14572  TrainID = Track->TrackElementAt(486, PrefDirElement.GetTrackVectorPosition()).TrainIDOnBridgeTrackPos01;
14573  }
14574  else
14575  {
14576  TrainID = Track->TrackElementAt(487, PrefDirElement.GetTrackVectorPosition()).TrainIDOnBridgeTrackPos23;
14577  }
14578  }
14579  else
14580  {
14581  TrainID = Track->TrackElementAt(488, PrefDirElement.GetTrackVectorPosition()).TrainIDOnElement;
14582  }
14583  if((TrainID > -1) && !(TrainController->TrainVectorAtIdent(4, TrainID).Stopped()))
14584  {
14585  Utilities->CallLogPop(100);
14586  return(true);
14587  }
14588  // check for crossed diagonal fouling by train added at v1.2.0
14589  int TrainID; // not used
14590  int LinkNumber1 = PrefDirElement.Link[PrefDirElement.GetELinkPos()];
14591  int LinkNumber2 = PrefDirElement.Link[PrefDirElement.GetXLinkPos()];
14592  if((LinkNumber1 == 1) || (LinkNumber1 == 3) || (LinkNumber1 == 7) || (LinkNumber1 == 9))
14593  {
14594  if(Track->DiagonalFouledByTrain(1, PrefDirElement.HLoc, PrefDirElement.VLoc, LinkNumber1, TrainID))
14595  {
14596  Utilities->CallLogPop(2037);
14597  return(true);
14598  }
14599  }
14600  if((LinkNumber2 == 1) || (LinkNumber2 == 3) || (LinkNumber2 == 7) || (LinkNumber2 == 9))
14601  {
14602  if(Track->DiagonalFouledByTrain(2, PrefDirElement.HLoc, PrefDirElement.VLoc, LinkNumber2, TrainID))
14603  {
14604  Utilities->CallLogPop(2038);
14605  return(true);
14606  }
14607  }
14608  }
14609  Utilities->CallLogPop(101);
14610  return(false);
14611 }
14612 
14613 // ---------------------------------------------------------------------------
14614 
14616 {
14617  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RevertToOriginalRouteSelector");
14618  AutoRouteStartMarker->PlotOriginal(26, Display); // if overlay not plotted will ignore
14619  SigRouteStartMarker->PlotOriginal(27, Display); // if overlay not plotted will ignore
14620  NonSigRouteStartMarker->PlotOriginal(28, Display); // if overlay not plotted will ignore
14621  RouteCancelFlag = false;
14623  {
14624  RouteCancelButton->Enabled = true;
14625  }
14626  else
14627  {
14628  RouteCancelButton->Enabled = false;
14629  }
14632 // reset here so that a n element that has been selected and then not doesn't remain set as a single element
14633  InfoPanel->Visible = true;
14634  if(Level2OperMode != Paused)
14635  {
14636  InfoPanel->Caption = InfoCaptionStore;
14637  }
14638  Utilities->CallLogPop(102);
14639 }
14640 
14641 // ---------------------------------------------------------------------------
14642 
14643 // usermode functions below
14644 void TInterface::SetLevel1Mode(int Caller)
14645 {
14646  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel1Mode");
14647  if(!Display->ZoomOutFlag)
14648  {
14651  Track->GapFlashFlag = false;
14652  }
14653 // GapFlash resets when any mode selected unless zoomed out
14654 // note that if selecting zoom back in then this will be called before ZoomOutFlag is reset so won't
14655 // reset GapFlashFlag
14656  switch(Level1Mode) // use the data member
14657  {
14658  case BaseMode:
14659  CopyMenuItem->ShortCut = TextToShortCut(""); // added these for v2.1.0 to set default values after use of the 'Edit' menu during track building
14660  CutMenuItem->ShortCut = TextToShortCut(""); // to allow normal cutting/copying/pasting, especially in timetable construction or editing
14661  PasteMenuItem->ShortCut = TextToShortCut("");
14666  LengthConversionPanel->Visible = false;
14667  SpeedConversionPanel->Visible = false;
14668  TimetableEditPanel->Visible = false;
14669  TrainController->TTEditPanelVisible = false; // added at v2.6.0 for two location message
14670  TrackBuildPanel->Visible = false;
14671  TrackElementPanel->Visible = false;
14672  LocationNameTextBox->Visible = false;
14673  TextBox->Visible = false;
14674  TrackLengthPanel->Visible = false;
14675  InfoPanel->Visible = false;
14676  PrefDirPanel->Visible = false;
14677  TimetablePanel->Visible = false;
14678  OperatingPanel->Visible = false;
14679  PrefDirKey->Visible = false;
14680  TrackLinkedImage->Visible = false;
14681  TrackNotLinkedImage->Visible = false;
14682  GapsSetImage->Visible = false;
14683  GapsNotSetImage->Visible = false;
14684  LocationNamesSetImage->Visible = false;
14685  LocationNamesNotSetImage->Visible = false;
14686  ModeMenu->Enabled = true;
14687  FileMenu->Enabled = true;
14688  EditMenu->Enabled = false;
14689  BuildTrackMenuItem->Enabled = true;
14690  SigAspectButton->Enabled = false;
14691  Track->ChangingLCVector.clear();
14692  Track->BarriersDownVector.clear();
14694  ConverttoRightHandSignalsMenuItem->Enabled = false; // new at v2.3.0
14695  SigImagePanel->Visible = false; // new at v2.3.0
14696  MTBFEditBox->Visible = false; // new at v2.4.0
14697  MTBFLabel->Visible = false;
14698  TTClockAdjustWarningPanel->Visible = false;
14699  if(Track->IsTrackFinished())
14700  {
14701  PlanPrefDirsMenuItem->Enabled = true;
14702  if(TimetableTitle != "")
14703  {
14704  OperateRailwayMenuItem->Enabled = true;
14705  }
14706  else
14707  {
14708  OperateRailwayMenuItem->Enabled = false;
14709  }
14710  }
14711  else
14712  {
14713  PlanPrefDirsMenuItem->Enabled = false;
14714  OperateRailwayMenuItem->Enabled = false;
14715  }
14716  if(RlyFile)
14717  {
14718  LoadTimetableMenuItem->Enabled = true;
14719  }
14720  else
14721  {
14722  LoadTimetableMenuItem->Enabled = false;
14723  }
14724  LoadRailwayMenuItem->Enabled = true;
14725  if(NoRailway())
14726  {
14727  SaveAsMenuItem->Enabled = false;
14728  ImageMenu->Enabled = false;
14729  SaveImageAndGridMenuItem->Enabled = false;
14730  SaveImageNoGridMenuItem->Enabled = false;
14731  SaveImageAndPrefDirsMenuItem->Enabled = false;
14732  SaveOperatingImageMenuItem->Enabled = false;
14733  BlackBgndMenuItem->Enabled = false;
14734  WhiteBgndMenuItem->Enabled = false;
14735  BlueBgndMenuItem->Enabled = false;
14736  ConverttoRightHandSignalsMenuItem->Enabled = true; // new at v2.3.0
14737  SigImagePanel->Visible = true; // new at v2.3.0
14738  if(Utilities->clTransparent != TColor(0))
14739  {
14740  BlackBgndMenuItem->Enabled = true;
14741  }
14742  if(Utilities->clTransparent != TColor(0xFFFFFF))
14743  {
14744  WhiteBgndMenuItem->Enabled = true;
14745  }
14746  if(Utilities->clTransparent != TColor(0x330000))
14747  {
14748  BlueBgndMenuItem->Enabled = true;
14749  }
14750  ClearAllMenuItem->Enabled = false;
14751  InfoPanel->Visible = true;
14752  InfoPanel->Caption = "Select an option from the File, Mode or Help menus";
14753  }
14754  else
14755  {
14756  InfoPanel->Visible = false;
14757  SaveAsMenuItem->Enabled = true;
14758  ImageMenu->Enabled = true;
14759  SaveImageAndGridMenuItem->Enabled = true;
14760  SaveImageNoGridMenuItem->Enabled = true;
14761  if(EveryPrefDir->PrefDirSize() > 0)
14762  {
14763  SaveImageAndPrefDirsMenuItem->Enabled = true;
14764  }
14765  else
14766  {
14767  SaveImageAndPrefDirsMenuItem->Enabled = false;
14768  }
14769  BlackBgndMenuItem->Enabled = false;
14770  WhiteBgndMenuItem->Enabled = false;
14771  BlueBgndMenuItem->Enabled = false;
14772  SaveOperatingImageMenuItem->Enabled = false;
14773  ClearAllMenuItem->Enabled = true;
14774  }
14775  if(SavedFileName == "")
14776  {
14777  SaveMenuItem->Enabled = false;
14778  }
14779  else if(!FileChangedFlag)
14780  {
14781  SaveMenuItem->Enabled = false;
14782  }
14783  else if((SavedFileName[SavedFileName.Length()] == 'y') || (SavedFileName[SavedFileName.Length()] == 'Y')) // 'rly' file
14784  {
14785  if(!(Track->IsReadyForOperation(false)))
14786  {
14787  SaveMenuItem->Enabled = false; // can't save under its old name as not now a .rly file
14788  }
14789  else
14790  {
14791  SaveMenuItem->Enabled = true; // must have changed some of the PrefDirs (because FileChangedFlag is true)
14792  }
14793  }
14794  else
14795  {
14796  SaveMenuItem->Enabled = true;
14797  }
14798  LoadSessionMenuItem->Enabled = true;
14799  ExitMenuItem->Enabled = true;
14800  ScreenGridFlag = false;
14801  TrainController->CrashWarning = false;
14802  TrainController->DerailWarning = false;
14803  TrainController->SPADWarning = false;
14805  TrainController->CallOnWarning = false;
14808  UserGraphicReselectPanel->Visible = false;
14809  ClearandRebuildRailway(32); // to get rid of unwanted displays (eg distance markers)
14810  SetTrackBuildImages(13);
14811  ClipboardChecked = false;
14812  break;
14813 
14814  case TimetableMode:
14815  if(TwoLocationNamePanel->Visible) //added at v2.9.1 so panel persists until button clicked
14816  {
14817  break;
14818  }
14822  ModeMenu->Enabled = false;
14823  SigImagePanel->Visible = false; // new at v2.3.0
14824  FileMenu->Enabled = false;
14825  EditMenu->Enabled = false;
14826  FloatingInfoMenu->Enabled = false;
14827  ImageMenu->Enabled = false;
14828  TimetableEditPanel->BringToFront();
14829  TimetableHandler();
14830  break;
14831 
14832  case TrackMode:
14833  {
14834  if(Level2TrackMode == CutMoving)
14835  {
14836  Level2TrackMode = Pasting; // paste the selection
14837  SetLevel2TrackMode(52); // CancelSelectionFlag used in Case Pasting
14838  }
14843  TrackBuildPanel->Visible = true;
14844  TrackBuildPanelLabel->Caption = "Build/modify";
14845  TrackElementPanel->Visible = false;
14846  TrackLengthPanel->Visible = false;
14847  PrefDirPanel->Visible = false;
14848  TimetablePanel->Visible = false;
14849  OperatingPanel->Visible = false;
14850  InfoPanel->Visible = false;
14851  InfoPanel->Caption = "";
14852  LocationNameTextBox->Visible = false;
14853  TextBox->Visible = false;
14854  ModeMenu->Enabled = false;
14855  SigImagePanel->Visible = false; // new at v2.3.0
14856  FileMenu->Enabled = false;
14857  // set edit menu items
14859  // display track buttons
14860  AddTrackButton->Enabled = true;
14862  {
14863  LocationNameButton->Enabled = true;
14864  }
14865  else
14866  {
14867  LocationNameButton->Enabled = false;
14868  }
14869  ScreenGridButton->Enabled = true;
14870  ExitTrackButton->Enabled = true;
14871  SetGapsButton->Enabled = false;
14872  TrackOKButton->Enabled = false;
14873  if(Track->GapsUnset(5))
14874  {
14875  SetGapsButton->Enabled = true;
14876  }
14877  // only enable if there are gaps still to be set (returns false for no track)
14878  else
14879  {
14880  if(!(Track->NoActiveTrack(2)) && !(Track->IsTrackFinished()))
14881  {
14882  TrackOKButton->Enabled = true;
14883  }
14884  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
14885  }
14886  SetLengthsButton->Enabled = false;
14887  if(Track->IsTrackFinished()) // can only set lengths for several elements together if TrackFinished
14888  {
14889  SetLengthsButton->Enabled = true;
14890  }
14891  // text buttons
14892  AddTextButton->Enabled = true;
14893  TextOrUserGraphicGridButton->Enabled = true;
14894  FontButton->Enabled = true;
14895  MoveTextOrGraphicButton->Enabled = false;
14896  if(TextHandler->TextVectorSize(9) > 0)
14897  {
14898  MoveTextOrGraphicButton->Enabled = true;
14899  }
14900  if(!Track->UserGraphicVector.empty())
14901  {
14902  MoveTextOrGraphicButton->Enabled = true;
14903  }
14904  SelectionValid = false;
14906  TimetableTitle = "";
14907  SetCaption(0);
14908  } break;
14909 
14910  case PrefDirMode:
14911  Screen->Cursor = TCursor(-11); //Hourglass in case many pref dirs
14915  PrefDirPanel->Visible = true;
14916  PrefDirPanelLabel->Caption = "Preferred direction selection";
14917 
14918  InfoPanel->Visible = true;
14919  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Select preferred direction start location (right click to erase)";
14920  PrefDirKey->Visible = true;
14921  ModeMenu->Enabled = false;
14922  SigImagePanel->Visible = false; // new at v2.3.0
14923  FileMenu->Enabled = false;
14924 // set edit menu items
14926  AddPrefDirButton->Enabled = false;
14927  DeleteOnePrefDirButton->Enabled = false;
14929  if(EveryPrefDir->PrefDirSize() > 0)
14930  {
14931  DeleteAllPrefDirButton->Visible = true;
14932  DeleteAllPrefDirButton->Enabled = true;
14933  SaveImageAndPrefDirsMenuItem->Enabled = true;
14934  }
14935  else
14936  {
14937  DeleteAllPrefDirButton->Enabled = false;
14938  SaveImageAndPrefDirsMenuItem->Enabled = false;
14939  }
14940  ExitPrefDirButton->Enabled = true;
14941  ClearandRebuildRailway(33); // to mark PrefDirs & clear earlier PrefDir markers
14942 // TimetableTitle = ""; no need to unload timetable if only PrefDirs being changed
14943 // SetCaption();
14944  Screen->Cursor = TCursor(-2); //Arrow
14945  break;
14946 
14947  case OperMode: // if there are any PrefDirs, set to SigPref, else to NoSigNonPref; start in Paused mode
14951  OperatingPanel->Visible = true;
14952  OperatingPanelLabel->Caption = "Operation";
14953 
14954  CallingOnButton->Visible = false;
14955  PresetAutoSigRoutesButton->Visible = true;
14956  if(!EveryPrefDir->PrefDirVector.empty()) //condition added at v2.10.0
14957  {
14958  PresetAutoSigRoutesButton->Enabled = true;
14959  }
14960  else
14961  {
14962  PresetAutoSigRoutesButton->Enabled = false;
14963  }
14964  InfoPanel->Visible = true;
14965  SigImagePanel->Visible = false; // new at v2.3.0
14966  ModeMenu->Enabled = false;
14967  FileMenu->Enabled = false;
14968  EditMenu->Enabled = false;
14969  ImageMenu->Enabled = true;
14970  SaveImageAndGridMenuItem->Enabled = true;
14971  SaveImageNoGridMenuItem->Enabled = true;
14972  if(EveryPrefDir->PrefDirSize() > 0)
14973  {
14974  SaveImageAndPrefDirsMenuItem->Enabled = true;
14975  }
14976  else
14977  {
14978  SaveImageAndPrefDirsMenuItem->Enabled = false;
14979  }
14980  SaveOperatingImageMenuItem->Enabled = true;
14981  AutoSigsFlag = false;
14982  MTBFEditBox->Visible = true; // visible at pre-start whether any value set or not, so can set a value if required
14984  {
14985  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
14986  }
14987  else
14988  {
14989  MTBFEditBox->Text = "";
14990  }
14991  MTBFEditBox->ReadOnly = false; // because this is prestart mode
14992  MTBFLabel->Visible = true;
14993  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
14995  if(EveryPrefDir->PrefDirSize() > 0)
14996  {
14997  ConsecSignalsRoute = true; // default starting conditions
14998  PreferredRoute = true; // default starting conditions
14999  }
15000  else // no PrefDirs
15001  {
15002  ConsecSignalsRoute = false;
15003  PreferredRoute = false;
15004  }
15005  OperateButton->Enabled = true;
15006  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
15007  ExitOperationButton->Enabled = true;
15008  TTClockAdjButton->Enabled = true;
15009  ShowPerformancePanel = false;
15010  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
15011  ShowOperatorActionPanel = false; // new at v2.2.0
15012  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel"); // new v2.2.0
15013 
15015 
15016  Utilities->Clock2Stopped = false;
15020  TTClockSpeed = 1;
15021  TTClockSpeedLabel->Caption = "x1";
15024 
15025  PerformanceFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
15026  // format "16/06/2009 20:55:17"
15027  // avoid characters in filename:= / \ : * ? " < > |
15028  PerformanceFileName = CurDir + "\\" + PERFLOG_DIR_NAME + "\\Log " + PerformanceFileName + "; " + RailwayTitle + "; " + TimetableTitle + ".txt";
15029 
15030  Utilities->PerformanceFile.open(PerformanceFileName.c_str(), std::ios_base::out);
15031  if(Utilities->PerformanceFile.fail())
15032  {
15033  ShowMessage("Performance logfile failed to open, logs won't be saved. Ensure that there is a folder named " + PERFLOG_DIR_NAME +
15034  " in the folder where the 'Railway.exe' program file resides");
15035  }
15036  Display->PerformanceLog(16, "Performance Log\nRailway: " + RailwayTitle + "\nTimetable: " + TimetableTitle + "\nStart Time: " +
15037  TrainController->TimetableStartTime.FormatString("hh:nn"));
15039 // DisableRouteButtons(2); enable route setting or pre-start
15040 // DisablePanelsStoreMainMenuStates();
15041  TrainController->ContinuationAutoSigVector.clear(); // for restarting after earlier run
15042  AllRoutes->LockedRouteVector.clear(); // for restarting after earlier run
15043 // TrainController->Operate(1);//plot trains that are present at TT start time, ready for running - no, allow route plotting prior to train entries
15044 
15045 // reset all performance indicators
15054  TrainController->OnTimeExits = 0; //these 3 exits added at v2.9.2 - missed in error earlier
15074 
15075  TrainController->OpActionPanelHintDelayCounter = 0; // new at v2.2.0 to reset hint delay
15076  OAListBox->Clear();
15077  OAListBox->Items->Add(L""); // hints for OpActionPanel
15078  OAListBox->Items->Add(L"");
15079  OAListBox->Items->Add(L"");
15080  OAListBox->Items->Add(L"Left click");
15081  OAListBox->Items->Add(L"headcode to");
15082  OAListBox->Items->Add(L"locate train");
15083  OAListBox->Items->Add(L"");
15084  OAListBox->Items->Add(L"");
15085  OAListBox->Items->Add(L"Right click");
15086  OAListBox->Items->Add(L"headcode for");
15087  OAListBox->Items->Add(L"information");
15088  OAListBox->Items->Add(L"");
15089  OAListBox->Items->Add(L"");
15090  OAListBox->Items->Add(L"Left click and");
15091  OAListBox->Items->Add(L"hold grey area");
15092  OAListBox->Items->Add(L"to move panel");
15093 
15094  ClearandRebuildRailway(55); // so points display with one fillet
15095  break;
15096 
15097  case RestartSessionOperMode: // restart in Paused mode after a session load, sets both Level1Mode & Level2OperMode
15098  Level1Mode = OperMode;
15099 // Level2OperMode = Paused; this is now loaded during LoadInterface & could be PreStart of Paused
15102  OperatingPanel->Visible = true;
15103  OperatingPanelLabel->Caption = "Operation";
15104 
15105  CallingOnButton->Visible = true;
15106  PresetAutoSigRoutesButton->Visible = false;
15107  InfoPanel->Visible = true;
15108  ModeMenu->Enabled = false;
15109  SigImagePanel->Visible = false; // new at v2.3.0
15110  FileMenu->Enabled = false;
15111  EditMenu->Enabled = false;
15112  ImageMenu->Enabled = true;
15113  SaveImageAndGridMenuItem->Enabled = true;
15114  SaveImageNoGridMenuItem->Enabled = true;
15115  if(EveryPrefDir->PrefDirSize() > 0)
15116  {
15117  SaveImageAndPrefDirsMenuItem->Enabled = true;
15118  }
15119  else
15120  {
15121  SaveImageAndPrefDirsMenuItem->Enabled = false;
15122  }
15123  SaveOperatingImageMenuItem->Enabled = true;
15124 
15125  OperateButton->Enabled = true;
15126  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
15127  ExitOperationButton->Enabled = true;
15128  TTClockAdjButton->Enabled = true;
15131  if(Level2OperMode == Paused)
15132  {
15133  DisableRouteButtons(3); // could be PreStart or Paused
15134  }
15139  TTClockSpeed = 1;
15140  TTClockSpeedLabel->Caption = "x1";
15142  ShowPerformancePanel = false; // added at v2.2.0
15143  ShowOperatorActionPanel = false; // new at v2.2.0
15144  TrainController->OpActionPanelHintDelayCounter = 0; // new at v2.2.0 to reset hint delay
15145  OAListBox->Clear();
15146  OAListBox->Items->Add(L""); // hints for OpActionPanel
15147  OAListBox->Items->Add(L"");
15148  OAListBox->Items->Add(L"");
15149  OAListBox->Items->Add(L"Left click");
15150  OAListBox->Items->Add(L"headcode to");
15151  OAListBox->Items->Add(L"locate train");
15152  OAListBox->Items->Add(L"");
15153  OAListBox->Items->Add(L"");
15154  OAListBox->Items->Add(L"Right click");
15155  OAListBox->Items->Add(L"headcode for");
15156  OAListBox->Items->Add(L"information");
15157  OAListBox->Items->Add(L"");
15158  OAListBox->Items->Add(L"");
15159  OAListBox->Items->Add(L"Left click and");
15160  OAListBox->Items->Add(L"hold grey area");
15161  OAListBox->Items->Add(L"to move panel");
15162  if((TrainController->AvHoursIntValue > 0) || (Level2OperMode == PreStart)) // only visible if already set or if still in prestart mode
15163  {
15164  MTBFEditBox->Visible = true;
15166  {
15167  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
15168  }
15169  else
15170  {
15171  MTBFEditBox->Text = "";
15172  }
15173  MTBFEditBox->ReadOnly = false; // because this is still prestart mode
15174  MTBFLabel->Visible = true;
15175  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
15177  }
15178  else
15179  {
15180  MTBFEditBox->Visible = false;
15181  MTBFEditBox->Text = "";
15182  MTBFEditBox->ReadOnly = true; // because this is not prestart mode
15183  MTBFLabel->Visible = false;
15184  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
15186  }
15187  break;
15188 
15189  default:
15190  // No further recursion in BaseMode so OK
15191  Level1Mode = BaseMode;
15192  SetLevel1Mode(29);
15193  break;
15194  }
15195  api_main_mode_ = int(Level1Mode); //added at v2.10.0
15196  session_api_->dump(); // update session INI file
15197  Utilities->CallLogPop(103);
15198 }
15199 
15200 // ---------------------------------------------------------------------------
15201 
15202 void TInterface::SetLevel2TrackMode(int Caller)
15203 {
15204  try
15205  {
15206  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2TrackMode");
15207  if(Level1Mode != TrackMode)
15208  {
15209  // No further recursion in BaseMode so OK
15210  Level1Mode = BaseMode;
15211  SetLevel1Mode(20);
15212  Utilities->CallLogPop(1115);
15213  return;
15214  }
15216  {
15217  Utilities->CallLogPop(104);
15218  return;
15219  }
15220  switch(Level2TrackMode) // use the data member
15221  {
15222  case AddTrack:
15224  InfoPanel->Visible = true;
15225  InfoPanel->Caption = "ADDING TRACK: Select element then left click to add it. Right click an element to remove it.";
15226  LengthConversionPanel->Visible = false; // in case had been in distance setting mode
15227  SpeedConversionPanel->Visible = false; // in case had been in distance setting mode
15228  TrackElementPanel->Visible = true;
15229  TrackElementPanel->Enabled = true;
15230  SigAspectButton->Visible = true;
15231  SigAspectButton->Enabled = true;
15232  ClearandRebuildRailway(34); // to replot grid if required & clear any other unwanted items
15234  SetLengthsButton->Enabled = false;
15235  // section added at v2.8.0 so buttons show correctly after a paste
15236  SetGapsButton->Enabled = false;
15237  TrackOKButton->Enabled = false;
15238  if(Track->GapsUnset(9))
15239  {
15240  SetGapsButton->Enabled = true;
15241  }
15242  // only enable if there are gaps still to be set (returns false for no track)
15243  else
15244  {
15245  if(!(Track->NoActiveTrack(3)) && !(Track->IsTrackFinished()))
15246  {
15247  TrackOKButton->Enabled = true;
15248  }
15249  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
15250  }
15251  // end of 2.8.0 addition
15252  if(Track->IsTrackFinished()) // can only set lengths for several elements together if TrackFinished
15253  {
15254  SetLengthsButton->Enabled = true;
15255  }
15256  UserGraphicReselectPanel->Visible = false;
15257  SelectLengthsFlag = false; // in case still set though probably won't be
15258  EditMenu->Enabled = true; // added at v2.6.0 to allow edits for an empty screen so track elements can fill a selected area
15259  SetTrackModeEditMenu(6); //added at v2.10.0 to set menu items
15260  break;
15261 
15262  case AddGraphic:
15263  InfoPanel->Visible = true;
15264  InfoPanel->Caption = "ADDING GRAPHIC: Left click layout to add SELECTED graphic, right click to remove ANY graphic.";
15265  break;
15266 
15267  case SelectGraphic:
15268  InfoPanel->Visible = true;
15269  InfoPanel->Caption = "SELECTING USER GRAPHIC: Select the graphic file then add as many as necessary to the layout.";
15270  break;
15271 
15272  case GapSetting:
15273  int HLoc, VLoc, Count;
15274  Count = Track->NumberOfGaps(0);
15275  if(div(Count, 2).rem == 1) // condition OK
15276  {
15277  ShowMessage("Can't connect, there are an odd number of gaps");
15279  SetLevel1Mode(77);
15281  // No further recursion in AddTrack so OK
15282  SetLevel2TrackMode(40);
15283  Utilities->CallLogPop(105);
15284  return;
15285  }
15286  if(!HighLightOneGap(2, HLoc, VLoc)) // condition OK
15287  // need to call this here to start gap setting process off,
15288  // called in MainScreenMouseDown hereafter. Function returns false for either a LocError (links not yet
15289  // complete) or no more gaps to be highlighted
15290  {
15291  // shouldn't reach here as later gaps covered in MainScreenMouseDown but leave & give error message
15292  ShowMessage("Error - Even number of gaps but all set after first call to HighLightOneGap");
15294  SetLevel1Mode(78);
15296  // No further recursion in AddTrack so OK
15297  SetLevel2TrackMode(41);
15298  Utilities->CallLogPop(106);
15299  return; // all gaps set
15300  }
15301  InfoPanel->Visible = true;
15302  InfoPanel->Caption = "CONNECTING GAPS: Click on connecting gap";
15303  UserGraphicReselectPanel->Visible = false;
15305  break;
15306 
15307  case AddText:
15308  InfoPanel->Visible = true;
15309  InfoPanel->Caption = "ADDING/EDITING TEXT: Left click to add, right click first letter to erase, or left click first letter to edit)";
15310  if(TextHandler->TextVectorSize(13) > 0)
15311  {
15312  MoveTextOrGraphicButton->Enabled = true;
15313  }
15314  else
15315  {
15316  MoveTextOrGraphicButton->Enabled = false;
15317  }
15318  UserGraphicReselectPanel->Visible = false;
15319  ClearandRebuildRailway(58); // to drop DistanceKey if was displayed
15320  break;
15321 
15322  case MoveTextOrGraphic:
15323  InfoPanel->Visible = true;
15324  InfoPanel->Caption = "MOVING TEXT OR GRAPHIC: If text left click first letter, if graphic left click anywhere, then drag";
15325  UserGraphicReselectPanel->Visible = false;
15326  ClearandRebuildRailway(59); // to drop DistanceKey if was displayed
15327  break;
15328 
15329  case AddLocationName:
15330  InfoPanel->Visible = true;
15331  InfoPanel->Caption = "NAMING LOCATIONS: Click on location element to add or change name";
15332  ClearandRebuildRailway(35); // to get rid of earlier red rectangle
15333  UserGraphicReselectPanel->Visible = false;
15334  SetTrackBuildImages(12);
15335  break;
15336 
15337  case DistanceStart:
15338  InfoPanel->Visible = true;
15339  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Select first location (only non-default elements marked)";
15340  DistanceKey->Visible = true;
15341  LengthConversionPanel->Visible = true;
15342  SpeedConversionPanel->Visible = true;
15343  UserGraphicReselectPanel->Visible = false;
15344  ClearandRebuildRailway(36); // to get rid of earlier unwanted markings
15345  break;
15346 
15347  case DistanceContinuing:
15348  InfoPanel->Visible = true;
15349  if(ConstructPrefDir->PrefDirSize() == 1)
15350  {
15351  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Select next location";
15352  }
15353  else
15354  {
15355  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
15356  }
15357  UserGraphicReselectPanel->Visible = false;
15358  ClearandRebuildRailway(54); // to remove earlier end marker if present
15359  break;
15360 
15361  case TrackSelecting:
15362  Track->CopyFlag = false;
15363  if(!SelectionValid)
15364  {
15365  ResetSelectRect(); // so a viewpoint change before a new SelectRect chosen doesn't redisplay
15366  }
15367  // the old SelectRect (only called when entered from SelectMenuItemClick, & not from
15368  // ReselectMenuItemClick)
15369  InfoPanel->Visible = true;
15370  InfoPanel->Caption = "SELECTING: Select area - click left mouse && drag";
15371  SelectMenuItem->Enabled = false;
15372  ReselectMenuItem->Enabled = false;
15373  CancelSelectionMenuItem->Enabled = true;
15374  UserGraphicReselectPanel->Visible = false;
15375  break;
15376 
15377  case CopyMoving:
15378  Track->CopyFlag = true;
15379  InfoPanel->Visible = true;
15380  InfoPanel->Caption = "COPYING: Left click in selection && drag";
15381  CutMenuItem->Enabled = false;
15382  CopyMenuItem->Enabled = false;
15383  FlipMenuItem->Enabled = false;
15384  MirrorMenuItem->Enabled = false;
15385  RotRightMenuItem->Enabled = false;
15386  RotLeftMenuItem->Enabled = false;
15387  RotateMenuItem->Enabled = false;
15388  PasteMenuItem->Enabled = true;
15389  // PasteWithAttributesMenuItem->Enabled = false; //new at v2.2.0 - don't allow the option if copying (dropped at 2.4.0 as all pastes are with attributes)
15390  DeleteMenuItem->Enabled = false;
15391  SelectLengthsMenuItem->Enabled = false;
15392  SelectBiDirPrefDirsMenuItem->Visible = false;
15393  CheckPrefDirConflictsMenuItem->Visible = false;
15394  CancelSelectionMenuItem->Enabled = true;
15398  UserGraphicReselectPanel->Visible = false;
15399  break;
15400 
15401  case CutMoving:
15402  {
15403  // have to use braces as otherwise the default case bypasses the initialisation of these local variables
15404  // erase track elements within selected region
15405  Track->CopyFlag = false;
15406  bool EraseSuccessfulFlag, NeedToLink = false, TextChangesMade = false, GraphicChangesMade = false;
15407  int ErasedTrackVectorPosition;
15408  Screen->Cursor = TCursor(-11); // Hourglass;
15409  InfoPanel->Visible = true;
15410  InfoPanel->Caption = "CUT PROCESSING: Please do not click the mouse";
15411  InfoPanel->Update();
15412  for(int H = SelectRect.left; H < SelectRect.right; H++)
15413  {
15414  for(int V = SelectRect.top; V < SelectRect.bottom; V++)
15415  {
15416  Track->EraseTrackElement(2, H, V, ErasedTrackVectorPosition, EraseSuccessfulFlag, false);
15417  if(EraseSuccessfulFlag)
15418  {
15419  if(ErasedTrackVectorPosition > -1) //may be an inactive element that was erased
15420  {
15421  EveryPrefDir->RealignAfterTrackErase(1, ErasedTrackVectorPosition);
15422  }
15423  NeedToLink = true;
15424  }
15425  }
15426  }
15427 
15428  // erase text elements within selected region
15429  int LowSelectHPos = SelectRect.left * 16;
15430  int HighSelectHPos = SelectRect.right * 16;
15431  int LowSelectVPos = SelectRect.top * 16;
15432  int HighSelectVPos = SelectRect.bottom * 16;
15433  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
15434  {
15435  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
15436  TextPtr--) // reverse to prevent skipping during erase
15437  {
15438  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
15439  HighSelectVPos))
15440  {
15441  if(TextHandler->TextErase(1, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
15442  {
15443  ;
15444  } // unused condition
15445 
15446  TextChangesMade = true;
15447  }
15448  }
15449  }
15450  // erase graphic elements that fall wholly within region to be overwritten
15451  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
15452  {
15453  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
15454  GraphicPtr--) // reverse to prevent skipping during erase
15455  {
15456  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
15457  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
15458  {
15459  Track->UserGraphicVector.erase(GraphicPtr);
15460  GraphicChangesMade = true;
15461  }
15462  }
15463  }
15464  Track->CheckMapAndTrack(11); // test
15465  Track->CheckMapAndInactiveTrack(10); // test
15466  Track->CheckLocationNameMultiMap(19); // test
15467  Screen->Cursor = TCursor(-2); // Arrow;
15468  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
15469  // if track not linked to begin with then becomes linked if NeedToLink false
15470  if(NeedToLink)
15471  {
15472  Track->SetTrackFinished(false); // corrected for v2.1.0
15473  }
15474  InfoPanel->Caption = "CUTTING: Left click in selection && drag";
15475  CutMenuItem->Enabled = false;
15476  CopyMenuItem->Enabled = false;
15477  FlipMenuItem->Enabled = false;
15478  MirrorMenuItem->Enabled = false;
15479  RotRightMenuItem->Enabled = false;
15480  RotLeftMenuItem->Enabled = false;
15481  RotateMenuItem->Enabled = false;
15482  PasteMenuItem->Enabled = true;
15483  // PasteWithAttributesMenuItem->Enabled = true; //new at v2.2.0 - option enabled if cutting (dropped at 2.4.0 as all pastes are with attributes)
15484  DeleteMenuItem->Enabled = false;
15485  SelectLengthsMenuItem->Enabled = false;
15486  SelectBiDirPrefDirsMenuItem->Visible = false;
15487  CheckPrefDirConflictsMenuItem->Visible = false;
15488  CancelSelectionMenuItem->Enabled = true;
15491  if(NeedToLink || TextChangesMade || GraphicChangesMade)
15492  {
15493  ResetChangedFileDataAndCaption(20, true); // true for NonPrefDirChangesMade
15494  }
15495  ClearandRebuildRailway(37); // to overplot the erased elements with SelectBitmap
15496  UserGraphicReselectPanel->Visible = false;
15498  } break;
15499 
15500  case Pasting:
15501  {
15502  // have to use braces as otherwise the default case bypasses the initialisation of these local variables
15503  int HDiff = SelectBitmapHLoc - SelectRect.left; // SelectBitmapHLoc/VLoc is the paste position & SelectRect.left/top is the original position
15504  int VDiff = SelectBitmapVLoc - SelectRect.top;
15505  if(!SelectionValid && !CancelSelectionFlag) // may be pasting into a new application so use clipboard, new at v2.8.0
15506  {
15507  bool ValidResult;
15508  RecoverClipboard(0, ValidResult); // new at v2.8.0
15509  if(ValidResult)
15510  {
15511  HDiff = Display->DisplayOffsetH - SelectRect.left; // SelectRect.left & top recovered in clipboard
15512  VDiff = Display->DisplayOffsetV - SelectRect.top;
15513  SelectBitmapHLoc = Display->DisplayOffsetH; // so the area to erase corresponds to the paste area (TLHC of screen = DisplayOffsetH & V)
15515  SelectionValid = false; // don't want reselect in new app after paste
15516  Track->SetTrackFinished(false); // would be set to false in other app but not in this so set it to false here
15518  {
15519  UnicodeString MessageStr =
15520  "Please be aware of the relevant conditions when pasting " "a railway segment from a different application.\n"
15521  "These are set out in section 3.5 of the manual and " "on-screen help under the heading 'Pasting in an application "
15522  "after cutting or copying from a different application'.\n\n" "This warning will not be shown again.\n\n" "Proceed?";
15523  int button = Application->MessageBox(MessageStr.c_str(), L"Warning", MB_YESNO | MB_ICONWARNING);
15525  if(button == IDNO)
15526  {
15527  CancelSelectionMenuItem->Click(); // reset clipboard etc
15528  Utilities->CallLogPop(2271);
15529  return;
15530  }
15531  }
15532  }
15533  else
15534  {
15535  Application->MessageBoxW(L"Unable to paste (clipboard is invalid) - possibly because another application has changed it)", L"Warning", MB_OK | MB_ICONWARNING);
15536  CancelSelectionMenuItem->Click(); // reset clipboard etc
15537  TrainController->LogEvent("ValidResult false in case Pasting - probably due to error in RecoverClipboard - see earlier log");
15538  Utilities->CallLogPop(2272); //EClipboardException (here as search term only)
15539  return;
15540  }
15541  }
15542  if(CancelSelectionFlag) // plot cut area in original position in case moved
15543  {
15546  HDiff = 0;
15547  VDiff = 0;
15548  }
15549  Clipboard()->Clear(); // already cleared & closed if recovered clipboard but not otherwise so clear & close here
15550  Clipboard()->Close();
15553  bool NeedToLink = false;
15554  bool TrackLinkingRequiredFlag;
15555  Screen->Cursor = TCursor(-11); // Hourglass;
15556  InfoPanel->Visible = true;
15557  InfoPanel->Caption = "PASTING: Please wait";
15558  InfoPanel->Update();
15559  // erase track elements
15560  int LowSelectHLoc = SelectBitmapHLoc;
15561  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
15562  int LowSelectVLoc = SelectBitmapVLoc;
15563  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
15564  bool TrackEraseSuccessfulFlag; // needed but not used here
15565  int ErasedTrackVectorPosition;
15566  // new quick method of erasing, only need H & V values
15567  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
15568  {
15569  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
15570  {
15571  Track->EraseTrackElement(5, x, y, ErasedTrackVectorPosition, TrackEraseSuccessfulFlag, false);
15572  if(ErasedTrackVectorPosition > -1)
15573  {
15574  EveryPrefDir->RealignAfterTrackErase(2, ErasedTrackVectorPosition);
15575  }
15576  }
15577  }
15578 
15579  // erase text elements that fall within region to be overwritten
15580  int LowSelectHPos = SelectBitmapHLoc * 16;
15581  int HighSelectHPos = (SelectBitmapHLoc * 16) + SelectBitmap->Width;
15582  int LowSelectVPos = SelectBitmapVLoc * 16;
15583  int HighSelectVPos = (SelectBitmapVLoc * 16) + SelectBitmap->Height;
15584  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
15585  {
15586  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
15587  TextPtr--) // reverse to prevent skipping during erase
15588  {
15589  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
15590  HighSelectVPos))
15591  {
15592  if(TextHandler->TextErase(2, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
15593  {
15594  ;
15595  } // unused condition
15596 
15597  }
15598  }
15599  }
15600  // erase graphic elements that fall wholly within region to be overwritten
15601  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
15602  {
15603  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
15604  GraphicPtr--) // reverse to prevent skipping during erase
15605  {
15606  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
15607  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
15608  {
15609  Track->UserGraphicVector.erase(GraphicPtr);
15610  }
15611  }
15612  }
15613  // change the H & V values in SelectVector to the new positions in case Reselect chosen
15614  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
15615  {
15616  Track->SelectVectorAt(35, x).HLoc += HDiff;
15617  Track->SelectVectorAt(1, x).VLoc += VDiff;
15618  }
15619 
15620  // add the new track elements
15621  AnsiString LocName;
15622  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
15623  {
15624  if(Track->CopyFlag) // blank all names if copying, lengths & speedlimits stay
15625  {
15626  Track->SelectVectorAt(80, x).LocationName = "";
15628  }
15629  else //cut, check if element has a name and if so remove same existing name from name map and track vector
15630  {
15631  LocName = Track->SelectVectorAt(82, x).LocationName;
15632  if(LocName == "")
15633  {
15634  LocName = Track->SelectVectorAt(83, x).ActiveTrackElementName;
15635  }
15636  if(LocName != "")
15637  {
15638  Track->EraseLocationAndActiveTrackElementNames(6, LocName); //this will keep erasing adjacent element names but the last one will be pasted and not erased
15639  //and that will name all linked elements so should work ok
15640  int HPos = 0, VPos = 0;
15641  if(TextHandler->FindText(5, LocName, HPos, VPos))
15642  {
15643  ;
15644  }
15645  {
15646  if(EraseLocationNameText(4, LocName, HPos, VPos))
15647  {
15648  ;
15649  } // condition not used
15650  }
15651  }
15652  }
15653  bool InternalChecks = false;
15654  // if(Track->PastingWithAttributes) //new at v2.2.0 to select the new funtion & skip multimap checks //drop in v2.4.0
15655  // {
15657  TrackLinkingRequiredFlag, InternalChecks);
15658  // new at v2.2.0 & used in place of PlotAndAddTrackElement to keep length & speed values
15659  // }
15660  /* drop this in v2.4.0 as all pastes are with attributes
15661  else //'Aspect' parameter added to PlotAndAdd... at v2.2.0 so can plot signals correctly (always four-aspect before)
15662  {
15663  int Aspect;
15664  if(Track->SelectVectorAt(15, x).TrackType != SignalPost) Aspect = 0; //if an '0' value appears with a SignalPost then must be adding track
15665  //this combination allows the funtion to distinguish between adding track and plotting with attributes
15666  else if(Track->SelectVectorAt(16, x).SigAspect == TTrackElement::GroundSignal) Aspect = 1;
15667  else if(Track->SelectVectorAt(17, x).SigAspect == TTrackElement::TwoAspect) Aspect = 2;
15668  else if(Track->SelectVectorAt(18, x).SigAspect == TTrackElement::ThreeAspect) Aspect = 3;
15669  else Aspect = 4;
15670  Track->PlotAndAddTrackElement(2, Track->SelectVectorAt(19, x).SpeedTag, Aspect, Track->SelectVectorAt(20, x).HLoc, Track->SelectVectorAt(21, x).VLoc, TrackLinkingRequiredFlag, InternalChecks);
15671  }
15672  */
15673  if(TrackLinkingRequiredFlag)
15674  {
15675  NeedToLink = true;
15676  }
15677  }
15678 
15679  //add the pref dir elements, added at v2.9.0
15680  int ATVecPos;
15681  bool FoundFlag;
15682  if(SelectPrefDir->PrefDirSize() > 0) // skip iteration if empty
15683  {
15684  // keep contents valid in case reselect
15686  PDVIt++)
15687  {
15688  PDVIt->HLoc += HDiff; // for reselect
15689  PDVIt->VLoc += VDiff; // for reselect
15690  //need to reset TrackVectorPosition in case any elements erased before linking, as if so EveryPrefDir can only be erased too if it has the correct TrackVectorPosition
15691  ATVecPos = Track->GetVectorPositionFromTrackMap(60, PDVIt->HLoc, PDVIt->VLoc, FoundFlag);
15692  if(!FoundFlag)
15693  {
15694  throw Exception("Failed to find TrackVectorPosition in PrefDir setting for Paste");
15695  }
15696  PDVIt->SetTrackVectorPosition(ATVecPos);
15697 
15698  //reset all Conns & ConnLinkPos values so won't be erased during a later cut, they will be set in RebuildPrefDirVector which is called when track linked
15699  for(int x = 0; x < 4; x++)
15700  {
15701  PDVIt->Conn[x] = -1;
15702  PDVIt->ConnLinkPos[x] = -1;
15703  }
15705  }
15707  }
15708 
15709  // add the new text items
15710  if(!TextHandler->SelectTextVector.empty()) // skip iteration if empty else have an error
15711  {
15712  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->SelectTextVector.begin(); TextPtr < TextHandler->SelectTextVector.end(); TextPtr++)
15713  {
15714  TextPtr->HPos += HDiff * 16;
15715  TextPtr->VPos += VDiff * 16;
15716  AnsiString TempString = TextPtr->TextString;
15717  // have to create a new TextItem in order to create a new Font object
15718  /* drop in v2.4.0 as all pastes are paste with attributes
15719  if(!Track->PastingWithAttributes) //new at v2.2.0 to deal with the new location prefix '##**' //drop in v2.4.0
15720  {
15721  if(TextPtr->TextString.SubString(1,4) != "##**") //added for named locations so can delete in a simple paste but
15722  //use in PastingWithAttributes
15723  {
15724  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, TextPtr->TextString, TextPtr->Font);
15725  TextHandler->TextVectorPush(0, TextItem); //if a normal paste include normal text but not location text
15726  }
15727  else TextPtr->TextString = ""; //delete the name for a simple paste
15728  }
15729  */
15730  // else //if pasting with attributes paste all text but strip the '##**' prefix if present
15731  // {
15732  if(TextPtr->TextString.SubString(1, 4) == "##**")
15733  {
15734  TempString = TextPtr->TextString.SubString(5, TextPtr->TextString.Length()); // don't change SelectTextVector value
15735  if(Track->CopyFlag)
15736  {
15737  TextPtr->TextString = ""; // change SelectTextVector value as reselect shouldn't have locations if copied
15738  TempString = "";
15739  }
15740  }
15741  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, TempString, TextPtr->Font);
15743  // }
15744  }
15745  }
15746  // add new graphic items
15747  if(!Track->SelectGraphicVector.empty()) // skip iteration if empty else have an error
15748  {
15749  // keep contents of SelectVector valid in case reselect
15750  for(TTrack::TUserGraphicVector::iterator GraphicPtr = Track->SelectGraphicVector.begin(); GraphicPtr < Track->SelectGraphicVector.end();
15751  GraphicPtr++)
15752  {
15753  GraphicPtr->HPos += HDiff * 16; // for reselect
15754  GraphicPtr->VPos += VDiff * 16; // for reselect
15755  Track->UserGraphicVector.push_back(*GraphicPtr);
15756  }
15757  }
15758  Track->SkipLocationNameMultiMapCheck = false; // renamed in v2.4.0 - reset the flag after pasting complete, otherwise multimap checks always skipped
15759  Track->CopyFlag = false;
15760  Track->CheckMapAndTrack(7); // test
15761  Track->CheckMapAndInactiveTrack(7); // test
15762  Track->CheckLocationNameMultiMap(7); // test
15763  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
15764  // if track not linked to begin with then becomes linked if NeedToLink false
15765  if(NeedToLink)
15766  {
15767  Track->SetTrackFinished(false); // corrected for v2.1.0
15768  }
15769  Screen->Cursor = TCursor(-2); // Arrow;
15770  SetTrackBuildImages(14);
15772  // Level1Mode = TrackMode; //dropped as prevents AddTrack being called to display track elements
15773  // SetLevel1Mode(79);
15774  SetTrackModeEditMenu(5); // this is called from the above but is still needed to enable Select (& Reselect if pasted in same app) menu items
15775  PasteMenuItem->Enabled = false;
15776  UserGraphicReselectPanel->Visible = false;
15777  if(Level2TrackMode != AddTrack) // no need to set if already set in an earlier call
15778  {
15780  // No further recursion in AddTrack so OK
15781  SetLevel2TrackMode(42);
15782  }
15783  } break;
15784 
15785  case Deleting:
15786  {
15787  // have to use braces as otherwise the default case bypasses the initialisation of these local variables
15788  Track->CopyFlag = false;
15789  UnicodeString MessageStr = "Selected area will be deleted - proceed?";
15790  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
15791  if(button == IDNO)
15792  {
15793  break;
15794  }
15795  bool EraseSuccessfulFlag, NeedToLink = false, TextChangesMade = false, GraphicChangesMade = false;
15796  int ErasedTrackVectorPosition;
15797  Screen->Cursor = TCursor(-11); // Hourglass;
15798  InfoPanel->Visible = true;
15799  InfoPanel->Caption = "DELETING: Please wait";
15800  InfoPanel->Update();
15801  for(int H = SelectRect.left; H < SelectRect.right; H++)
15802  {
15803  for(int V = SelectRect.top; V < SelectRect.bottom; V++)
15804  {
15805  Track->EraseTrackElement(3, H, V, ErasedTrackVectorPosition, EraseSuccessfulFlag, false);
15806  if(EraseSuccessfulFlag)
15807  {
15808  if(ErasedTrackVectorPosition > -1)
15809  {
15810  EveryPrefDir->RealignAfterTrackErase(3, ErasedTrackVectorPosition);
15811  }
15812  NeedToLink = true;
15813  }
15814  }
15815  }
15816  // erase text elements that fall within selected region
15817  int LowSelectHPos = SelectRect.left * 16;
15818  int HighSelectHPos = SelectRect.right * 16;
15819  int LowSelectVPos = SelectRect.top * 16;
15820  int HighSelectVPos = SelectRect.bottom * 16;
15821  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
15822  {
15823  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
15824  TextPtr--) // reverse to prevent skipping during erase
15825  {
15826  AnsiString Check = TextPtr->TextString;
15827  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
15828  HighSelectVPos))
15829  {
15830  if(TextHandler->TextErase(3, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
15831  {
15832  ;
15833  } // unused condition
15834 
15835  TextChangesMade = true;
15836  }
15837  }
15838  }
15839  // erase graphic elements that fall within selected region
15840  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
15841  {
15842 
15843  // Isglassen05 (vilhelmgg@gmail.com) reported an error via email and attached an error file on 31/07/20. The error was in the following line which was:
15844 
15845  // for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->SelectGraphicVector.end() - 1); GraphicPtr >= Track->SelectGraphicVector.begin();
15846  // GraphicPtr--) // reverse to prevent skipping during erase
15847 
15848  // i.e if the railway included one or more user graphics but the SelectGraphicVector didn't include any, then GraphicPtr wouldn't point to anything and the program would fail
15849  // corrected 01/08/20 by using UserGraphicVector (as it should have been) for SelectGraphicVector. New version v2.4.3.
15850 
15851  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
15852  GraphicPtr--) // reverse to prevent skipping during erase
15853  {
15854  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
15855  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
15856  {
15857  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = (Track->UserGraphicVector.end() - 1);
15858  UserGraphicPtr >= Track->UserGraphicVector.begin(); UserGraphicPtr--) // reverse to prevent skipping during erase
15859  {
15860  if((UserGraphicPtr->HPos == GraphicPtr->HPos) && (UserGraphicPtr->VPos == GraphicPtr->VPos) &&
15861  (UserGraphicPtr->Width == GraphicPtr->Width) && (UserGraphicPtr->Height == GraphicPtr->Height) &&
15862  (UserGraphicPtr->FileName == GraphicPtr->FileName))
15863  {
15864  Track->UserGraphicVector.erase(UserGraphicPtr);
15865  GraphicChangesMade = true;
15866  }
15867  }
15868  }
15869  }
15870  }
15871  // clear the selectvectors
15873  TextHandler->SelectTextVector.clear();
15874  Track->SelectGraphicVector.clear();
15876  Track->CheckMapAndTrack(10); // test
15877  Track->CheckMapAndInactiveTrack(9); // test
15878  Track->CheckLocationNameMultiMap(15); // test
15879  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
15880  // if track not linked to begin with then becomes linked if NeedToLink false
15881  if(NeedToLink)
15882  {
15883  Track->SetTrackFinished(false); // corrected for v2.1.0
15884  }
15885  if(NeedToLink || TextChangesMade || GraphicChangesMade)
15886  {
15887  ResetChangedFileDataAndCaption(21, true); // true for NonPrefDirChangesMade
15888  }
15889  Screen->Cursor = TCursor(-2); // Arrow;
15892  SetLevel1Mode(80);
15894  // No further recursion in AddTrack so OK
15895  UserGraphicReselectPanel->Visible = false;
15896  SetLevel2TrackMode(43);
15897  } break;
15898 
15899  default:
15900  // No further recursion in TrackMode so OK
15901  Track->CopyFlag = false;
15903  SetLevel1Mode(21);
15904  UserGraphicReselectPanel->Visible = false;
15905  break;
15906  }
15907  Utilities->CallLogPop(107);
15908  }
15909  catch (const EClipboardException &e) //non-error catch
15910  {
15911  TrainController->LogEvent("Clipboard error in SetLevel2TrackMode");
15912  }
15913 }
15914 
15915 // ---------------------------------------------------------------------------
15916 
15917 void TInterface::SetLevel2PrefDirMode(int Caller)
15918 {
15919  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2PrefDirMode");
15920  if(Level1Mode != PrefDirMode)
15921  {
15922  // No further recursion in BaseMode so OK
15923  Level1Mode = BaseMode;
15924  SetLevel1Mode(22);
15925  Utilities->CallLogPop(108);
15926  return;
15927  }
15929  {
15930  Utilities->CallLogPop(109);
15931  return;
15932  }
15933  switch(Level2PrefDirMode) // use the data member
15934  {
15935  case PrefDirContinuing:
15936  {
15937  // have to use braces as otherwise the default case bypasses the initialisation of these local variables
15938  InfoPanel->Visible = true;
15939  if(!Display->ZoomOutFlag) // can't set focus if zoomed out, get an error - added this condition for v0.4d
15940  {
15941  AddPrefDirButton->Enabled = true; // this and the line below are to remove focus from any other button that might have it, prior to
15942  AddPrefDirButton->SetFocus(); // disabling the AddPrefDir button, so pressing enter does nothing, it is reset to the AddPrefDir
15943  }
15944  AddPrefDirButton->Enabled = false; // button later if it becomes enabled
15945  DeleteOnePrefDirButton->Enabled = false;
15946  bool LeadingPointsAtLastElement = false;
15947  if(!ConstructPrefDir->EndPossible(0, LeadingPointsAtLastElement))
15948  {
15949  if(LeadingPointsAtLastElement) // size must be > 1
15950  {
15951  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Can't end on leading points, select next location or truncate";
15952  DeleteOnePrefDirButton->Enabled = true;
15953  }
15954  else // size == 1, DeleteOnePrefDirButton->Enabled remains false
15955  {
15956  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Select next preferred direction location (right click to truncate)";
15957  }
15958  }
15959  else // size > 1 & EndPossible
15960  {
15961  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Add selection or select next location (right click to truncate)";
15962  if(!Display->ZoomOutFlag) // can't set focus if zoomed out, get an error - added this condition for v0.4d
15963  {
15964  AddPrefDirButton->Enabled = true;
15965  AddPrefDirButton->SetFocus(); // so can just press 'Enter' key
15966  }
15967  DeleteOnePrefDirButton->Enabled = true;
15968  }
15969  ExitPrefDirButton->Enabled = true;
15970  ClearandRebuildRailway(40); // to show truncated PrefDirs
15971  } break;
15972 
15973  case PrefDirSelecting:
15974  ResetSelectRect(); // so a viewpoint change before a new SelectRect chosen doesn't redisplay the old SelectRect
15975  InfoPanel->Visible = true;
15976  InfoPanel->Caption = "SELECTING: Select area - click left mouse && drag";
15977  SelectMenuItem->Enabled = false;
15978  ReselectMenuItem->Enabled = false;
15979  CancelSelectionMenuItem->Enabled = true;
15980  break;
15981 
15982  default:
15983  // No further recursion in PrefDirMode so OK
15985  SetLevel1Mode(23);
15986  break;
15987  }
15988  Utilities->CallLogPop(110);
15989 }
15990 
15991 // ---------------------------------------------------------------------------
15992 
15993 void TInterface::SetLevel2OperMode(int Caller)
15994 {
15995  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2OperMode");
15996  if(Level1Mode != OperMode)
15997  {
15998  // No further recursion in BaseMode so OK
15999  Level1Mode = BaseMode;
16000  SetLevel1Mode(24);
16001  Utilities->CallLogPop(111);
16002  return;
16003  }
16004  if(Level2OperMode == NoOperMode)
16005  {
16006  Utilities->CallLogPop(112);
16007  return;
16008  }
16009  CallingOnButton->Visible = true;
16010  PresetAutoSigRoutesButton->Visible = false;
16011  switch(Level2OperMode) // use the data member
16012  {
16013  case Operating:
16014  {
16015  // have to use braces as otherwise the default case bypasses the initialisation of local variables
16016  OperateButton->Enabled = true;
16017  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
16018  ExitOperationButton->Enabled = true;
16019  TTClockAdjButton->Enabled = false;
16020  if(TTClockSpeed == 2)
16021  {
16022  TTClockSpeedLabel->Caption = "x2";
16023  }
16024  else if(TTClockSpeed == 4)
16025  {
16026  TTClockSpeedLabel->Caption = "x4";
16027  }
16028  else if(TTClockSpeed == 8)
16029  {
16030  TTClockSpeedLabel->Caption = "x8";
16031  }
16032  else if(TTClockSpeed == 16)
16033  {
16034  TTClockSpeedLabel->Caption = "x16";
16035  }
16036  else if(TTClockSpeed == 0.5)
16037  {
16038  TTClockSpeedLabel->Caption = "x1/2";
16039  }
16040  else if(TTClockSpeed == 0.25)
16041  {
16042  TTClockSpeedLabel->Caption = "x1/4";
16043  }
16044  else if(TTClockSpeed == 0.125)
16045  {
16046  TTClockSpeedLabel->Caption = "x1/8";
16047  }
16048  else if(TTClockSpeed == 0.0625)
16049  {
16050  TTClockSpeedLabel->Caption = "x1/16";
16051  }
16052  else
16053  {
16054  TTClockSpeed = 1;
16055  TTClockSpeedLabel->Caption = "x1";
16056  }
16057  AnsiString TimeMessage = Utilities->Format96HHMMSS(TDateTime(PauseEntryRestartTime)) + ": ";
16059  {
16060  // send message to performance log
16061  if(TTClockSpeed == 2)
16062  {
16063  Display->PerformanceLog(6, TimeMessage + "Timetable clock speed changed to twice normal");
16064  }
16065  else if(TTClockSpeed == 4)
16066  {
16067  Display->PerformanceLog(7, TimeMessage + "Timetable clock speed changed to four times normal");
16068  }
16069  else if(TTClockSpeed == 8)
16070  {
16071  Display->PerformanceLog(8, TimeMessage + "Timetable clock speed changed to eight times normal");
16072  }
16073  else if(TTClockSpeed == 16)
16074  {
16075  Display->PerformanceLog(9, TimeMessage + "Timetable clock speed changed to sixteen times normal");
16076  }
16077  else if(TTClockSpeed == 0.5)
16078  {
16079  Display->PerformanceLog(10, TimeMessage + "Timetable clock speed changed to half normal");
16080  }
16081  else if(TTClockSpeed == 0.25)
16082  {
16083  Display->PerformanceLog(11, TimeMessage + "Timetable clock speed changed to quarter normal");
16084  }
16085  else if(TTClockSpeed == 0.125)
16086  {
16087  Display->PerformanceLog(14, TimeMessage + "Timetable clock speed changed to one eighth normal");
16088  }
16089  else if(TTClockSpeed == 0.0625)
16090  {
16091  Display->PerformanceLog(15, TimeMessage + "Timetable clock speed changed to one sixteenth normal");
16092  }
16093  else
16094  {
16095  Display->PerformanceLog(12, TimeMessage + "Timetable clock speed changed to normal");
16096  }
16097  }
16098  double TTClockTimeChange = double(TrainController->RestartTime) - PauseEntryRestartTime;
16099  if(TTClockTimeChange > 0.000347) // 30 seconds, min increase is 1 minute & don't trust doubles to stay exactly equal
16100  {
16101  // send message to performance log
16102  int MinsIncrease = ((TTClockTimeChange * 1440) + 0.5); // add 30 secs to ensure truncates correctly
16103  int HoursIncrease = 0;
16104  while(MinsIncrease >= 60)
16105  {
16106  HoursIncrease++;
16107  MinsIncrease -= 60;
16108  }
16109  if(HoursIncrease == 0)
16110  {
16111  TimeMessage += "Timetable clock incremented by " + AnsiString(MinsIncrease) + "m";
16112  }
16113  else if(MinsIncrease == 0)
16114  {
16115  TimeMessage += "Timetable clock incremented by " + AnsiString(HoursIncrease) + "h";
16116  }
16117  else
16118  {
16119  TimeMessage += "Timetable clock incremented by " + AnsiString(HoursIncrease) + "h " + AnsiString(MinsIncrease) + "m";
16120  }
16121  Display->PerformanceLog(13, TimeMessage);
16122  }
16123  WarningHover = false;
16126  {
16127  MTBFEditBox->Visible = true;
16128  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
16129  MTBFEditBox->ReadOnly = true; // because this is not prestart mode
16130  MTBFLabel->Visible = true;
16131  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
16133  }
16134  else
16135  {
16136  MTBFEditBox->Visible = false;
16137  MTBFEditBox->Text = "";
16138  MTBFLabel->Visible = false;
16139  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
16141  }
16142  TrainController->BaseTime = TDateTime::CurrentDateTime();
16143 // StopTTClockFlag already false because TTClock stopped by condition "if(!TrainController->StopTTClockFlag && (Level2OperMode == Operating))" in MasterClockTimer function
16144  } break;
16145 
16146  case Paused:
16147  OperateButton->Enabled = true;
16148  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
16149  ExitOperationButton->Enabled = true;
16150  TTClockAdjButton->Enabled = true;
16155 // StopTTClockFlag stays false because TTClock stopped by condition "if(!TrainController->StopTTClockFlag && (Level2OperMode == Operating))" in MasterClockTimer function
16158  break;
16159 
16160  // don't need a separate case for PreStart
16161 
16162  default:
16163  // No further recursion in OperMode so OK
16164  Level1Mode = OperMode;
16165  SetLevel1Mode(25);
16166  break;
16167  }
16168  api_oper_mode_ = int(Level2OperMode); //added at v2.10.0
16169  session_api_->dump(); // update session INI file
16170  Utilities->CallLogPop(113);
16171 }
16172 
16173 // ---------------------------------------------------------------------------
16174 
16175 void TInterface::ApproachLocking(int Caller, TDateTime TTClockTime)
16176 {
16177  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ApproachLocking");
16178  float LockDelay = 120.0;
16179 
16180  if(!AllRoutes->LockedRouteVector.empty())
16181  {
16182  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
16183  {
16184  bool BreakFlag = false;
16185  if(AllRoutes->TrackIsInARoute(5, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
16186  {
16187  TOneRoute &Route = AllRoutes->GetModifiableRouteAt(0, LRVIT->RouteNumber);
16188  if((TTClockTime - LRVIT->LockStartTime) > TDateTime(LockDelay / 86400))
16189  {
16190  TrainController->LogEvent("LockedRouteRemoved," + AnsiString(LRVIT->TruncateTrackVectorPosition) + "," +
16191  AnsiString(LRVIT->LastTrackVectorPosition));
16192  while(Route.LastElementPtr(9)->GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
16193  {
16194  // examine the element one earlier in the route than the last
16195  if(!(AllRoutes->TrackIsInARoute(6, Route.LastElementPtr(10)->Conn[Route.LastElementPtr(11)->GetELinkPos()],
16196  Route.LastElementPtr(12)->ConnLinkPos[Route.LastElementPtr(13)->GetELinkPos()])))
16197  {
16198  BreakFlag = true;
16199  }
16200  AllRoutes->RemoveRouteElement(1, Route.LastElementPtr(14)->HLoc, Route.LastElementPtr(15)->VLoc, Route.LastElementPtr(16)->GetELink());
16201  if(BreakFlag)
16202  {
16203  break; // train removed earlier element from route so stop here
16204  }
16205  }
16206  if(!BreakFlag)
16207  {
16208  // still need to remove the element at the TruncateTrackVectorPosition
16209  if(Route.LastElementPtr(17)->GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
16210  {
16211  AllRoutes->RemoveRouteElement(2, Route.LastElementPtr(18)->HLoc, Route.LastElementPtr(19)->VLoc,
16212  Route.LastElementPtr(20)->GetELink());
16213  }
16214  }
16215  AllRoutes->CheckMapAndRoutes(10); // test
16216  AllRoutes->LockedRouteVector.erase(LRVIT);
16217  if(!Display->ZoomOutFlag)
16218  {
16219  ClearandRebuildRailway(17); // to get rid of route graphics
16220  }
16222  }
16223  }
16224  else
16225  {
16226  AllRoutes->LockedRouteVector.erase(LRVIT);
16227  // if end element not in route then a train must have entered it from the wrong end and erased the whole route,
16228  // hence no longer needed so get rid of it
16229  }
16230  }
16231  }
16232  Utilities->CallLogPop(743);
16233 }
16234 
16235 // ---------------------------------------------------------------------------
16236 
16237 void TInterface::ContinuationAutoSignals(int Caller, TDateTime TTClockTime)
16238 {
16239  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ContinuationAutoSignals");
16241  {
16243  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
16244  AutoSigVectorIT--)
16245  {
16246  // Below added at v2.1.0 to prevent locked autosig continuation routes from clearing signals
16247  // need to identify the Continuation element in the route & check if it's in a locked route. If it is then don't call
16248  // SetTrailingSignalsOnContinuationRoute as all signals must stay red.
16249  TPrefDirElement TempPrefDirElement;
16250  int TempLockedVectorNumber;
16251  int LastRouteElement = AllRoutes->GetFixedRouteAt(220, AutoSigVectorIT->RouteNumber).PrefDirSize() - 1;
16252  int TVNum = AllRoutes->GetFixedRouteAt(221, AutoSigVectorIT->RouteNumber).GetFixedPrefDirElementAt(246, LastRouteElement).GetTrackVectorPosition();
16253  // this will be a continuation (error thrown in SetTrailingSignalsOnContinuationRoute if not) & XLinkPos is always 0 for
16254  // route exiting at a continuation
16255  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(14, TVNum, 0, TempPrefDirElement, TempLockedVectorNumber))
16256  {
16257  continue;
16258  }
16259  // end of additions
16260  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->FirstDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 0))
16261  {
16262  AllRoutes->SetTrailingSignalsOnContinuationRoute(1, AutoSigVectorIT->RouteNumber, 0);
16263  AutoSigVectorIT->AccessNumber++;
16264  continue;
16265  }
16266  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->SecondDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 1))
16267  {
16268  AllRoutes->SetTrailingSignalsOnContinuationRoute(2, AutoSigVectorIT->RouteNumber, 1);
16269  AutoSigVectorIT->AccessNumber++;
16270  continue;
16271  }
16272  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->ThirdDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 2))
16273  {
16274  AllRoutes->SetTrailingSignalsOnContinuationRoute(3, AutoSigVectorIT->RouteNumber, 2);
16275  AutoSigVectorIT->AccessNumber++;
16276  continue;
16277  }
16278  }
16279  // examine all vector for any expired values & erase
16280  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
16281  AutoSigVectorIT--)
16282  {
16283  if(AutoSigVectorIT->AccessNumber > 2)
16284  {
16285  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT); // erase expired entries - reverse interation so OK to erase
16286  }
16287  }
16288  }
16289  Utilities->CallLogPop(744);
16290 }
16291 
16292 // ---------------------------------------------------------------------------
16293 
16294 void TInterface::TrackTrainFloat(int Caller)
16295 {
16296  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackTrainFloat");
16297  TPoint MousePoint = Mouse->CursorPos;
16298  int ScreenX = MousePoint.x - MainScreen->ClientOrigin.x;
16299  int ScreenY = MousePoint.y - MainScreen->ClientOrigin.y;
16300 
16301  if(!OAListBoxRightMouseButtonDown && ((ScreenX > (MainScreen->Width - 1)) || (ScreenY > (MainScreen->Height - 1)) || (ScreenX < 0) || (ScreenY < 0)))
16302  {
16303  // added !OAListBoxRightMouseButtonDown at v2.7.0 so can still obtain info & move to trains from OAListBox even if they are out of the main screen area
16304  FloatingPanel->Visible = false;
16305  Utilities->CallLogPop(1432);
16306  return;
16307  }
16308  if(PerformancePanel->Visible)
16309  {
16310  if((MousePoint.x >= PerformancePanel->Left) && (MousePoint.x <= (PerformancePanel->Left + PerformancePanel->Width)) &&
16311  ((MousePoint.y - ClientOrigin.y) >= PerformancePanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
16312  (PerformancePanel->Top + PerformancePanel->Height)))
16313  {
16314  // dont show floating window if mouse over performance panel
16315  FloatingPanel->Visible = false;
16316  Utilities->CallLogPop(1715);
16317  return;
16318  }
16319  }
16320  if(TimetableEditPanel->Visible) // added at v2.5.1 as showed track info behind panel
16321  {
16322  if((MousePoint.x >= TimetableEditPanel->Left) && (MousePoint.x <= (TimetableEditPanel->Left + TimetableEditPanel->Width)) &&
16323  ((MousePoint.y - ClientOrigin.y) >= TimetableEditPanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
16324  (TimetableEditPanel->Top + TimetableEditPanel->Height)))
16325  {
16326  // dont show floating window if mouse over TimetableEditPanel
16327  FloatingPanel->Visible = false;
16328  Utilities->CallLogPop(2240);
16329  return;
16330  }
16331  }
16332  AnsiString TrackFloat = "", TrainStatusFloat = "", TrainTTFloat = "";
16333  bool ShowTrackFloatFlag = false, ShowTrainStatusFloatFlag = false, ShowTrainTTFloatFlag = false;
16334  int HLoc, VLoc;
16335 
16336  Track->GetTrackLocsFromScreenPos(4, HLoc, VLoc, ScreenX, ScreenY);
16337 
16338  if(Display->ZoomOutFlag)
16339  {
16340  Utilities->CallLogPop(1123);
16341  return;
16342  }
16343  bool MouseOverOAPanel = false;
16344 // this flag added at v2.7.0 in place of prohibition of all floating windows (which was added at v2.3.0 when Xeon notified me in email of 15/10/19 that they were showing)
16345  if(OperatorActionPanel->Visible)
16346  {
16347  if((MousePoint.x >= OperatorActionPanel->Left) && (MousePoint.x <= (OperatorActionPanel->Left + OperatorActionPanel->Width)) &&
16348  ((MousePoint.y - ClientOrigin.y) >= OperatorActionPanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
16349  (OperatorActionPanel->Top + OperatorActionPanel->Height)))
16350  {
16351  MouseOverOAPanel = true;
16352  }
16353  }
16354  if((TrackInfoOnOffMenuItem->Caption == "Hide") && !MouseOverOAPanel)
16355  // MouseOverOAPanel condit added at v2.7.0 in place of prohibition of all floating windows (which was added at v2.3.0 when Xeon notified me in email of 15/10/19 that they were showing)
16356  {
16357  bool ActiveTrackFoundFlag = false, InactiveTrackFoundFlag = false, TwoTrack = false;
16358  AnsiString Length01Str = "", Length23Str = "", SpeedLimit01Str = "", SpeedLimit23Str = "";
16359  AnsiString StationEntryStopLinkPos1Str = "", StationEntryStopLinkPos2Str = "";
16360  AnsiString ATrackSN = "", ATrackTN = "", IATrackSN = "", LengthAndSpeedCaption = "";
16361  AnsiString SigAspectString = ""; // new at version 0.6
16362  int ActiveVecPos = Track->GetVectorPositionFromTrackMap(5, HLoc, VLoc, ActiveTrackFoundFlag);
16363  TTrack::TIMPair InactiveVecPositions = Track->GetVectorPositionsFromInactiveTrackMap(3, HLoc, VLoc, InactiveTrackFoundFlag);
16364  TTrackElement ActiveTrackElement, InactiveTrackElement;
16365  if(InactiveTrackFoundFlag)
16366  {
16367  InactiveTrackElement = Track->InactiveTrackElementAt(32, InactiveVecPositions.first); // only need one for the name
16368  IATrackSN = InactiveTrackElement.LocationName;
16369  }
16370  if(ActiveTrackFoundFlag)
16371  {
16372  ActiveTrackElement = Track->TrackElementAt(449, ActiveVecPos);
16373  ATrackSN = ActiveTrackElement.LocationName;
16374  StationEntryStopLinkPos1Str = AnsiString(ActiveTrackElement.StationEntryStopLinkPos1);
16375  StationEntryStopLinkPos2Str = AnsiString(ActiveTrackElement.StationEntryStopLinkPos2);
16376  ATrackTN = ActiveTrackElement.ActiveTrackElementName;
16377  if((ATrackTN != "") && (!InactiveTrackFoundFlag || ((InactiveTrackElement.TrackType != Platform) &&
16378  (InactiveTrackElement.TrackType != NamedNonStationLocation)) ||
16379  (InactiveTrackElement.LocationName != ActiveTrackElement.ActiveTrackElementName)))
16380  {
16381  ShowMessage("Error - Track has timetable name without corresponding plat/named loc");
16382  }
16383  if(InactiveTrackFoundFlag && ((InactiveTrackElement.TrackType == Platform) || (InactiveTrackElement.TrackType == NamedNonStationLocation)) &&
16384  (InactiveTrackElement.LocationName != ActiveTrackElement.ActiveTrackElementName))
16385  {
16386  ShowMessage("Error - plat/named loc and track have different names, or plat/named loc named but not track");
16387  }
16388  if((ActiveTrackElement.TrackType == Points) || (ActiveTrackElement.TrackType == Bridge) || (ActiveTrackElement.TrackType == Crossover))
16389  {
16390  TwoTrack = true;
16391  }
16392  Length01Str = AnsiString(ActiveTrackElement.Length01);
16393  if(Length01Str == "-1")
16394  {
16395  Length01Str = "Not Set";
16396  }
16397  SpeedLimit01Str = AnsiString(ActiveTrackElement.SpeedLimit01);
16398  if(SpeedLimit01Str == "-1")
16399  {
16400  SpeedLimit01Str = "Not Set";
16401  }
16402  if(TwoTrack)
16403  {
16404  Length23Str = AnsiString(ActiveTrackElement.Length23);
16405  if(Length23Str == "-1")
16406  {
16407  Length23Str = "Not Set"; // shouldn't be -1 but leave in
16408  }
16409  SpeedLimit23Str = AnsiString(ActiveTrackElement.SpeedLimit23);
16410  if(SpeedLimit23Str == "-1")
16411  {
16412  SpeedLimit23Str = "Not Set"; // shouldn't be -1 but leave in
16413  }
16414  if((ActiveTrackElement.TrackType == Points) && (ActiveTrackElement.SpeedTag < 132))
16415  {
16416  LengthAndSpeedCaption = "Straight track length = " + Length01Str + " m" + '\n' + "Diverging track length = " + Length23Str + " m" + '\n' +
16417  "Straight track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Diverging track speed limit = " + SpeedLimit23Str + " km/h";
16418  }
16419  else if(ActiveTrackElement.TrackType == Points)
16420  {
16421  LengthAndSpeedCaption = "Left diverging track length = " + Length01Str + " m" + '\n' + "Right diverging track length = " + Length23Str +
16422  " m" + '\n' + "Left diverging track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Right diverging track Speed Limit = " +
16423  SpeedLimit23Str + " km/h";
16424  }
16425  else if(ActiveTrackElement.TrackType == Crossover)
16426  // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
16427  {
16428  if((ActiveTrackElement.SpeedTag == 15) || (ActiveTrackElement.SpeedTag == 46))
16429  {
16430  LengthAndSpeedCaption = "Horizontal track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str + " m" + '\n' +
16431  "Horizontal track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit23Str + " km/h";
16432  }
16433  else if(ActiveTrackElement.SpeedTag == 47)
16434  {
16435  LengthAndSpeedCaption = "Horizontal track length = " + Length23Str + " m" + '\n' + "Other track length = " + Length01Str + " m" + '\n' +
16436  "Horizontal track speed limit = " + SpeedLimit23Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit01Str + " km/h";
16437  }
16438  else if(ActiveTrackElement.SpeedTag == 45)
16439  {
16440  LengthAndSpeedCaption = "Vertical track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str + " m" + '\n' +
16441  "Vertical track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit23Str + " km/h";
16442  }
16443  else if(ActiveTrackElement.SpeedTag == 44)
16444  {
16445  LengthAndSpeedCaption = "Vertical track length = " + Length23Str + " m" + '\n' + "Other track length = " + Length01Str + " m" + '\n' +
16446  "Vertical track speed limit = " + SpeedLimit23Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit01Str + " km/h";
16447  }
16448  else if(ActiveTrackElement.SpeedTag == 16)
16449  {
16450  LengthAndSpeedCaption = "Top left to bottom right track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str +
16451  " m" + '\n' + "Top left to bottom right track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " +
16452  SpeedLimit23Str + " km/h";
16453  }
16454  }
16455  else // bridge
16456  {
16457  LengthAndSpeedCaption = "Top track length = " + Length01Str + " m" + '\n' + "Bottom track length = " + Length23Str + " m" + '\n' +
16458  "Top track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Bottom track speed limit = " + SpeedLimit23Str + " km/h";
16459  }
16460  }
16461  else
16462  {
16463  LengthAndSpeedCaption = "Track length = " + Length01Str + " m" + '\n' + "Track speed limit = " + SpeedLimit01Str + " km/h";
16464  }
16465  }
16466  if(ActiveTrackFoundFlag)
16467  {
16468  // note that now the "In timetable..." line removed much of the below could be simplified, but leave as is
16469  // in case wish to resurrect this line for any reason
16470  ShowTrackFloatFlag = true;
16471  if(ATrackTN != "") // has a timetable name & therefore has a valid platform or non-station name
16472  {
16473  TrackFloat = "Location = " + ATrackTN + '\n' + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
16474  }
16475  else if(ATrackSN != "") // no timetable name but location name, i.e. a footcrossing
16476  {
16477  TrackFloat = "Location = " + ATrackSN + '\n' + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
16478  }
16479 
16480  else if(InactiveTrackFoundFlag) // no timetable name yet but unnamed inactive element at same location (can't be a parapet if active element there)
16481  {
16482  TrackFloat = "Location unnamed\n" + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
16483  }
16484 
16485  else // no timetable or location name, just track
16486  {
16487  TrackFloat = LengthAndSpeedCaption + '\n' + "Track Element ID = " + AnsiString(ActiveTrackElement.ElementID);
16488  }
16489  if(ActiveTrackElement.TrackType == SignalPost) // new for version 0.6
16490  {
16491  if(ActiveTrackElement.SigAspect == TTrackElement::ThreeAspect)
16492  {
16493  SigAspectString = "\nThree-aspect signal";
16494  }
16495  else if(ActiveTrackElement.SigAspect == TTrackElement::TwoAspect)
16496  {
16497  SigAspectString = "\nTwo-aspect signal";
16498  }
16499  else if(ActiveTrackElement.SigAspect == TTrackElement::GroundSignal)
16500  {
16501  SigAspectString = "\nGround signal";
16502  }
16503  else
16504  {
16505  SigAspectString = "\nFour-aspect signal";
16506  }
16507  TrackFloat += SigAspectString;
16508  }
16509  } // if(ActiveFoundFlag)
16510  else if(InactiveTrackFoundFlag) // inactive element but no active element,
16511  // i.e. concourse or non-station name at a blank element
16512  {
16513  ShowTrackFloatFlag = true;
16514  if(InactiveTrackElement.TrackType != Parapet)
16515  {
16516  if(IATrackSN == "")
16517  {
16518  TrackFloat = "Location unnamed\nID = " + AnsiString(InactiveTrackElement.ElementID);
16519  }
16520  else
16521  {
16522  TrackFloat = "Location = " + IATrackSN + '\n' + "ID = " + AnsiString(InactiveTrackElement.ElementID);
16523  }
16524  }
16525  else // it is a parapet, just show the ID
16526  {
16527  TrackFloat = "ID = " + AnsiString(InactiveTrackElement.ElementID);
16528  }
16529  }
16530  }
16531 // end of TrackFloat section
16532 
16533  bool OAListBoxFloatRequired = false; // identifies which window needs the float
16534  if(Level1Mode == OperMode && ((TrainStatusInfoOnOffMenuItem->Caption == "Hide Status") || (TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")))
16535  // if caption is 'Hide' label is required
16536  {
16537  bool FoundFlag;
16538  AnsiString FormatOneDPStr = "####0.0";
16539  AnsiString FormatNoDPStr = "#######0";
16540 // AnsiString Format5DPStr = "####0.00000"; //temporary
16541  AnsiString MaxBrakeStr = ""; // , EntrySpeedStr="", HalfStr="", FullStr="", MaxAtHalfStr="";//test
16542  AnsiString SpecialStr = "";
16543  if(OperatorActionPanel->Visible) // added at v2.6.2 to show floating window for trains in actions due list
16544  {
16545  if(OAListBox->MouseInClient && !OperatorActionPanel->MouseInClient && OAListBoxRightMouseButtonDown)
16546  {
16547  int X = OAListBox->ScreenToClient(MousePoint).x;
16548  int Y = OAListBox->ScreenToClient(MousePoint).y;
16549  int TrainID = -1, ContinuationPos = -1;
16550  if(GetTrainIDOrContinuationPosition(1, X, Y, TrainID, ContinuationPos))
16551  {
16552  OAListBoxFloatRequired = true;
16553  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
16554  {
16555  ShowTrainStatusFloatFlag = true;
16556  }
16557  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
16558  {
16559  ShowTrainTTFloatFlag = true;
16560  }
16561  if((TrainID > -1) && (ShowTrainStatusFloatFlag || ShowTrainTTFloatFlag))
16562  {
16563  TTrain Train = TrainController->TrainVectorAtIdent(53, TrainID);
16564  TrainStatusFloat = GetTrainStatusFloat(0, TrainID, FormatNoDPStr, SpecialStr);
16565  TrainTTFloat = Train.FloatingTimetableString(1, Train.ActionVectorEntryPtr);
16566  }
16567  else if(ContinuationPos > -1)
16568  {
16569  GetTrainFloatingInfoFromContinuation(0, ContinuationPos, FormatNoDPStr, SpecialStr, TrainStatusFloat, TrainTTFloat);
16570  }
16571  }
16572  }
16573  }
16574  if(!OAListBoxFloatRequired) // condition added at v2.6.2 so only one floating window can show
16575  {
16576  int VecPos = Track->GetVectorPositionFromTrackMap(6, HLoc, VLoc, FoundFlag);
16577  if(FoundFlag && !MouseOverOAPanel) // MouseOverOAPanel added at v2.7.0 to prevent trains showimng behind OA panel
16578  {
16579  if(Track->TrackElementAt(450, VecPos).TrainIDOnElement > -1)
16580  // if a bridge & 2 trains at that position will select the train with TrainIDOnElement set
16581  {
16582  int TrainID = Track->TrackElementAt(452, VecPos).TrainIDOnElement;
16583  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
16584  {
16585  ShowTrainStatusFloatFlag = true;
16586  TrainStatusFloat = GetTrainStatusFloat(1, TrainID, FormatNoDPStr, SpecialStr);
16587  }
16588  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
16589  {
16590  ShowTrainTTFloatFlag = true;
16591  TTrain Train = TrainController->TrainVectorAtIdent(54, TrainID);
16592  TrainTTFloat = Train.FloatingTimetableString(0, Train.ActionVectorEntryPtr);
16593  }
16594  }
16595 
16596  else if(Track->TrackElementAt(666, VecPos).TrackType == Continuation)
16597  // always give train information if a train present, but if not & either of train status or timetable info
16598  // selected then give next expected train to enter, or 'No trains expected'
16599  {
16600  TrainStatusFloat = "No trains expected";
16601  TrainTTFloat = "No timetable";
16602  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
16603  {
16604  ShowTrainStatusFloatFlag = true;
16605  }
16606  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
16607  {
16608  ShowTrainTTFloatFlag = true;
16609  }
16611  {
16612  GetTrainFloatingInfoFromContinuation(1, VecPos, FormatNoDPStr, SpecialStr, TrainStatusFloat, TrainTTFloat);
16613  }
16614  }
16615  }
16616  }
16617  }
16618 // end of TrainFloat section
16619  AnsiString Caption;
16620 
16621  if(!ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
16622  {
16623  FloatingPanel->Visible = false;
16624  Utilities->CallLogPop(1485);
16625  return; // return with label invisible
16626  }
16627  else if(ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
16628  {
16629  Caption = TrackFloat;
16630  }
16631  else if(!ShowTrackFloatFlag && ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
16632  {
16633  Caption = TrainStatusFloat;
16634  }
16635  else if(ShowTrackFloatFlag && ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
16636  {
16637  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
16638  }
16639  else if(!ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
16640  {
16641  if(TrainStatusFloat == "No trains expected")
16642  {
16643  Caption = TrainStatusFloat;
16644  }
16645  else
16646  {
16647  Caption = TrainTTFloat;
16648  }
16649  }
16650  else if(ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
16651  {
16652  if(TrainStatusFloat == "No trains expected")
16653  {
16654  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
16655  }
16656  else
16657  {
16658  Caption = TrainTTFloat + '\n' + '\n' + TrackFloat;
16659  }
16660  }
16661  else if(!ShowTrackFloatFlag && ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
16662  {
16663  if(TrainStatusFloat == "No trains expected")
16664  {
16665  Caption = TrainStatusFloat;
16666  }
16667  else
16668  {
16669  Caption = TrainStatusFloat + '\n' + '\n' + TrainTTFloat;
16670  }
16671  }
16672  else if(ShowTrackFloatFlag && ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
16673  {
16674  if(TrainStatusFloat == "No trains expected")
16675  {
16676  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
16677  }
16678  else
16679  {
16680  Caption = TrainStatusFloat + '\n' + '\n' + TrainTTFloat + '\n' + '\n' + TrackFloat;
16681  }
16682  }
16683  int WindowOffsetLeft = 16;
16684  int WindowOffsetRight = 16;
16685  if(OAListBoxFloatRequired)
16686  {
16687  WindowOffsetLeft = 32;
16688  WindowOffsetRight = 64;
16689  }
16690  FloatingLabel->Caption = Caption; // set this here so dimensions correct in calculations, moved from below at v2.7.0
16691  FloatingPanel->Visible = true; // need this or dimensions still not valid, moved from below at v2.7.0
16692 
16693  int Left = ScreenX + MainScreen->Left + WindowOffsetRight; // so lhs of window is WindowOffset to the right of the mouse pos
16694 // this offset is because window position is relative to the interface form, whereas ScreenX & Y are relative to the MainScreen, which is
16695 // offset 32 to the right and 95 down from the interface form
16696  if((Left + FloatingPanel->Width) > MainScreen->Left + MainScreen->Width)
16697  {
16698  Left = ScreenX - FloatingPanel->Width + 32 - WindowOffsetLeft;
16699  }
16700 // so rhs of window is 32 - WindowOffset to the left of the mouse pos (+32 would be at mouse pos)
16701  int Top = ScreenY + MainScreen->Top + 16; // so top of window is one element below the mouse pos (ScreenY + MainScreen->Top would be at mouse pos)
16702 
16703  if((Top + FloatingPanel->Height) > MainScreen->Top + MainScreen->Height)
16704  {
16705  Top = ScreenY - FloatingPanel->Height + 79; // so bottom of window is one element above the mouse pos (95 would be at mouse pos)
16706  // but, top may now be off the top of the screen, if so position at the top of the screen, as always need to see the top, if have to
16707  // lose something then it's best to be from the bottom
16708  if(Top < 30) // use 30 instead of MainScreen->Top [95] as top can go off MainScreen providing it doesn't reach the information panel, as that would
16709  // obscure the window
16710  {
16711  Top = 30;
16712  }
16713  }
16714 /* if((Left != FloatingPanel->Left) || (Top != FloatingPanel->Top)) //dropped at v2.7.0 as causes more flickler than allowing window to move with mouse
16715  {
16716  FloatingPanel->Visible = false; // so doesn't flicker when reposition
16717  FloatingPanel->Left = Left;
16718  FloatingPanel->Top = Top;
16719  Utilities->CallLogPop(1917);
16720  return;
16721  }
16722 */
16723 
16724  FloatingPanel->Left = Left; // new at v2.7.0 in place of above
16725  FloatingPanel->Top = Top;
16726 
16727 // FloatingLabel->Caption = Caption; moved up at v2.7.0
16728 // FloatingPanel->Visible = true; // moved up at v2.7.0
16729  FloatingPanel->BringToFront();
16730  Utilities->CallLogPop(746);
16731 }
16732 
16733 // ---------------------------------------------------------------------------
16734 
16735 void TInterface::GetTrainFloatingInfoFromContinuation(int Caller, int VecPos, AnsiString FormatNoDPStr, AnsiString SpecialStr, AnsiString &TrainStatusFloat,
16736  AnsiString &TrainTTFloat)
16737 {
16738  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrainFloatingInfoFromContinuation");
16740  int LineSpeedLimit = Track->TrackElementAt(906, VecPos).SpeedLimit01; // speed only in 01 as a continuation
16741  float EntrySpeed;
16743  {
16744  while((CTEIt != TrainController->ContinuationTrainExpectationMultiMap.end()) && ((CTEIt->second.VectorPosition != VecPos) ||
16745  (CTEIt->second.TrainDataEntryPtr->TrainOperatingDataVector.at(CTEIt->second.RepeatNumber).RunningEntry != NotStarted)))
16746  {
16747  CTEIt++;
16748  }
16750  {
16751  TTrainDataEntry *TTDEPtr = CTEIt->second.TrainDataEntryPtr;
16752  AnsiString ServiceReferenceInfo = "";
16753  // Repeat information
16754  if(TTDEPtr->NumberOfTrains > 1) // Service reference information
16755  {
16756  if(CTEIt->second.RepeatNumber == 0)
16757  {
16758  if(CTEIt->second.HeadCode != TTDEPtr->ServiceReference)
16759  {
16760  ServiceReferenceInfo = "\nFirst service of ref. " + TTDEPtr->ServiceReference;
16761  }
16762  else
16763  {
16764  ServiceReferenceInfo = "\nFirst service";
16765  }
16766  }
16767  else if(CTEIt->second.HeadCode == TTDEPtr->ServiceReference)
16768  {
16769  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(CTEIt->second.RepeatNumber);
16770  }
16771  else
16772  {
16773  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(CTEIt->second.RepeatNumber) + " of ref. " + TTDEPtr->ServiceReference;
16774  }
16775  }
16776  else
16777  {
16778  if(CTEIt->second.HeadCode != TTDEPtr->ServiceReference)
16779  {
16780  ServiceReferenceInfo = "\nService reference " + TTDEPtr->ServiceReference;
16781  }
16782  }
16783  if(TTDEPtr->ActionVector.at(0).SignallerControl) // entry at 0 is the start entry
16784  {
16785  SpecialStr = "\nTrain under signaller control";
16786  EntrySpeed = TTDEPtr->SignallerSpeed;
16787  if(EntrySpeed > LineSpeedLimit)
16788  {
16789  EntrySpeed = LineSpeedLimit;
16790  }
16791  }
16792  else
16793  {
16794  EntrySpeed = TTDEPtr->StartSpeed;
16795  if(EntrySpeed > LineSpeedLimit)
16796  {
16797  EntrySpeed = LineSpeedLimit;
16798  }
16799  }
16800  if((CTEIt->first + TDateTime(1.0 / 1440)) < TrainController->TTClockTime) // has to be at least 1 min late to show as late
16801  {
16802  TDateTime TempTime = CTEIt->first;
16803 // need this because CTEIt points to a const object and shouldn't use FormatString on a const object
16804  TrainStatusFloat = CTEIt->second.HeadCode + ": " + CTEIt->second.Description + ServiceReferenceInfo + "\nEntry speed " +
16805  AnsiString::FormatFloat(FormatNoDPStr, EntrySpeed) + "km/h" + SpecialStr + "\nDelayed, was due at " + Utilities->Format96HHMM(TempTime);
16806  }
16807  else
16808  {
16809  TDateTime TempTime = CTEIt->first;
16810 // need this because CTEIt points to a const object and shouldn't use FormatString on a const object
16811  TrainStatusFloat = CTEIt->second.HeadCode + ": " + CTEIt->second.Description + ServiceReferenceInfo + "\nEntry speed " +
16812  AnsiString::FormatFloat(FormatNoDPStr, EntrySpeed) + "km/h" + SpecialStr + "\nExpected at " + Utilities->Format96HHMM(TempTime);
16813  }
16814  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
16815  {
16816  if(!TTDEPtr->ActionVector.at(0).SignallerControl) // if signaller control there's no timetable & SpecialStr covers this
16817  {
16818  TrainTTFloat = TrainController->ContinuationEntryFloatingTTString(0, TTDEPtr, CTEIt->second.RepeatNumber, CTEIt->second.IncrementalMinutes,
16819  CTEIt->second.IncrementalDigits);
16820  }
16821  }
16822  }
16823  }
16824  Utilities->CallLogPop(2262);
16825 }
16826 
16827 // ---------------------------------------------------------------------------
16828 
16829 AnsiString TInterface::GetTrainStatusFloat(int Caller, int TrainID, AnsiString FormatNoDPStr, AnsiString SpecialStr)
16830 // new at v2.6.2 to make it easier to show also from actions due panel
16831 {
16832  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrainStatusFloat");
16833  AnsiString HeadCode = "", ServiceReferenceInfo = "", Status = "", CurrSpeedStr = "", BrakePCStr = "", NextStopStr = "", TimeLeftStr = "",
16834  TimeToNextMovementStr = "", MassStr = "", PowerStr = "";
16835  AnsiString FormatOneDPStr = "####0.0", MaxBrakeStr = "", MaxSpeedStr = "", TrainStatusFloat;
16836 
16837  double CurrSpeed;
16838  TTrain Train = TrainController->TrainVectorAtIdent(1, TrainID);
16839  MassStr = AnsiString::FormatFloat(FormatNoDPStr, ((double)Train.Mass) / 1000); // Te
16840  PowerStr = AnsiString::FormatFloat(FormatNoDPStr, Train.PowerAtRail / 1000 / 0.8); // kW
16841  if(Train.BeingCalledOn)
16842  {
16843  MaxSpeedStr = "30";
16844  }
16845  else
16846  {
16847  MaxSpeedStr = AnsiString::FormatFloat(FormatNoDPStr, Train.MaxRunningSpeed);
16848  }
16849  TDateTime ElapsedDeltaT = TrainController->TTClockTime - Train.EntryTime;
16850  TDateTime FirstHalfTimeDeltaT = Train.ExitTimeHalf - Train.EntryTime;
16851  TDateTime SecondHalfTimeDeltaT = Train.ExitTimeFull - Train.EntryTime - FirstHalfTimeDeltaT;
16852  TDateTime TimeLeft;
16853  double BrakePCRate = Train.BrakeRate * 100.0 / Train.MaxBrakeRate;
16854  MaxBrakeStr = AnsiString::FormatFloat(FormatNoDPStr, (Train.MaxBrakeRate * Train.Mass / 9810));
16855  HeadCode = Train.HeadCode;
16856  if(Train.TrainDataEntryPtr->NumberOfTrains > 1) // Service reference information added at v0.6b
16857  {
16858  if(Train.RepeatNumber == 0)
16859  {
16860  if(HeadCode != Train.TrainDataEntryPtr->ServiceReference)
16861  {
16862  ServiceReferenceInfo = "\nFirst service of ref. " + Train.TrainDataEntryPtr->ServiceReference;
16863  }
16864  else
16865  {
16866  ServiceReferenceInfo = "\nFirst service";
16867  }
16868  }
16869  else if(HeadCode == Train.TrainDataEntryPtr->ServiceReference)
16870  {
16871  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(Train.RepeatNumber);
16872  }
16873  else
16874  {
16875  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(Train.RepeatNumber) + " of ref. " + Train.TrainDataEntryPtr->ServiceReference;
16876  }
16877  }
16878  else
16879  {
16880  if(HeadCode != Train.TrainDataEntryPtr->ServiceReference)
16881  {
16882  ServiceReferenceInfo = "\nService reference " + Train.TrainDataEntryPtr->ServiceReference;
16883  }
16884  }
16885  if(Train.Stopped())
16886  {
16887  if(Train.SignallerStopped)
16888  {
16889  Status = "Stopped on signaller's instruction"; // if stopped for any other reason that will diplay
16890  }
16891  if(Train.NotInService)
16892  {
16893  Status = "Not in service"; // not used so far but leave it in
16894  }
16895  if(Train.StoppedAtBuffers)
16896  {
16897  Status = "Stopped at buffers";
16898  }
16899  if(Train.StoppedAtSignal)
16900  {
16901  Status = "Stopped at signal";
16902  }
16903  if(Train.StoppedForTrainInFront)
16904  {
16905  Status = "Stopped - forward track occupied"; // before station stop as want to display station stop if that set
16906  }
16907  if(Train.StoppedAtLocation)
16908  {
16909  Status = "Stopped at " + Train.ActionVectorEntryPtr->LocationName;
16910  }
16911  if((Train.StoppedAtLocation) && (Train.StoppedForTrainInFront))
16912  {
16913  Status = "Stopped at " + Train.ActionVectorEntryPtr->LocationName + " + forward track occupied";
16914  }
16915  if(Train.StoppedWithoutPower)
16916  {
16917  if(Train.TrainFailed)
16918  {
16919  Status = "Stopped without power - train failed";
16920  }
16921  else
16922  {
16923  Status = "Stopped without power";
16924  }
16925  }
16926  if(Train.StoppedAfterSPAD)
16927  {
16928  Status = "Stopped - signal passed at danger";
16929  }
16930  if(Train.Derailed)
16931  {
16932  Status = "Derailed";
16933  }
16934  if(Train.Crashed)
16935  {
16936  Status = "Crashed";
16937  }
16938  CurrSpeed = 0;
16939  }
16940  else if(Train.OneLengthAccelDecel)
16941  {
16942  if(Train.FirstHalfMove)
16943  {
16944  Status = "Accelerating"; // just display a linear speed rise over half length
16945  BrakePCRate = 0; // reset to proper value during braking
16946  CurrSpeed = Train.EntrySpeed + ((Train.ExitSpeedHalf - Train.EntrySpeed) * (double(ElapsedDeltaT) / double(FirstHalfTimeDeltaT)));
16947  }
16948  else
16949  {
16950  BrakePCRate = Train.BrakeRate * 100.0 / Train.MaxBrakeRate;
16951  if(BrakePCRate < 55)
16952  {
16953  Status = "Light braking";
16954  }
16955  else if(BrakePCRate < 90)
16956  {
16957  Status = "Heavy braking";
16958  }
16959  else
16960  {
16961  Status = "Emergency braking";
16962  }
16963  CurrSpeed = Train.ExitSpeedHalf - 3.6 * (Train.BrakeRate * (TrainController->TTClockTime - Train.ExitTimeHalf) * 86400.0);
16964  }
16965  }
16966  else if(Train.BrakeRate > 0.01)
16967  {
16968  if(BrakePCRate < 55)
16969  {
16970  Status = "Light braking";
16971  }
16972  else if(BrakePCRate < 90)
16973  {
16974  Status = "Heavy braking";
16975  }
16976  else
16977  {
16978  Status = "Emergency braking";
16979  }
16980  CurrSpeed = Train.EntrySpeed - 3.6 * (Train.BrakeRate * ElapsedDeltaT * 86400.0);
16981  }
16982 
16983  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedHalf > (Train.EntrySpeed + 0.01)) && Train.FirstHalfMove)
16984  {
16985  Status = "Accelerating"; // just display a linear speed rise over half length
16986  CurrSpeed = Train.EntrySpeed + ((Train.ExitSpeedHalf - Train.EntrySpeed) * (double(ElapsedDeltaT) / double(FirstHalfTimeDeltaT)));
16987  }
16988 
16989  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedFull > (Train.ExitSpeedHalf + 0.01)) && !Train.FirstHalfMove)
16990  {
16991  Status = "Accelerating";
16992  CurrSpeed = Train.ExitSpeedHalf +
16993  ((Train.ExitSpeedFull - Train.ExitSpeedHalf) * (double(ElapsedDeltaT - FirstHalfTimeDeltaT) / double(SecondHalfTimeDeltaT)));
16994  }
16995 
16996  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedFull <= Train.ExitSpeedHalf) && !Train.FirstHalfMove)
16997  {
16998  if(Train.PowerAtRail < 1)
16999  {
17000  if(Train.TrainFailed)
17001  {
17002  Status = "Coasting - train failed";
17003  }
17004  else
17005  {
17006  Status = "Coasting - no power";
17007  }
17008  CurrSpeed = Train.ExitSpeedFull;
17009  }
17010  else
17011  {
17012  Status = "Constant speed";
17013  CurrSpeed = Train.ExitSpeedFull;
17014  }
17015  }
17016 
17017  else // No braking, first half move, ExitSpeedHalf <= EntrySpeed
17018  {
17019  if(Train.PowerAtRail < 1) // as designed there is no way a vehicle can coast without having failed
17020  {
17021  if(Train.TrainFailed)
17022  {
17023  Status = "Coasting - train failed";
17024  }
17025  else
17026  {
17027  Status = "Coasting - no power";
17028  }
17029  CurrSpeed = Train.ExitSpeedHalf;
17030  }
17031  else
17032  {
17033  Status = "Constant speed";
17034  CurrSpeed = Train.ExitSpeedHalf;
17035  }
17036  }
17037  if(Train.TimetableFinished)
17038  {
17039  if(Train.TrainMode == Signaller)
17040  {
17041  NextStopStr = "At signaller's discretion";
17042  }
17043  else
17044  {
17045  NextStopStr = "None";
17046  }
17047  }
17048  else
17049  {
17050  NextStopStr = Train.FloatingLabelNextString(0, Train.ActionVectorEntryPtr);
17051  }
17052  if(Train.TrainMode == Signaller)
17053  {
17054  SpecialStr = "Train under signaller control" + AnsiString('\n');
17055  }
17056  else if(Train.BeingCalledOn && !Train.StoppedAtLocation)
17057  {
17058  SpecialStr = "Restricted speed - being called on" + AnsiString('\n');
17059  }
17060  double RemTimeHalf = 86400.0 * double(Train.ExitTimeHalf - TrainController->TTClockTime);
17061  if(RemTimeHalf < 0)
17062  {
17063  RemTimeHalf = 0;
17064  }
17065  double RemTimeFull = 86400.0 * double(Train.ExitTimeFull - TrainController->TTClockTime);
17066  if(RemTimeFull < 0)
17067  {
17068  RemTimeFull = 0;
17069  }
17070  if(RemTimeHalf > 0)
17071  {
17072  TimeLeft = RemTimeHalf;
17073  }
17074  else
17075  {
17076  TimeLeft = RemTimeFull;
17077  }
17078  TimeToNextMovementStr = "Time to next movement (sec) = " + TimeLeftStr.FormatFloat(FormatOneDPStr, TimeLeft);
17079  if(Train.Stopped())
17080  {
17081  TimeToNextMovementStr = "";
17082  }
17083  if(Train.Stopped())
17084  {
17085  TrainStatusFloat = HeadCode + ": " + Train.TrainDataEntryPtr->Description + ServiceReferenceInfo + '\n' + "Maximum train speed " + MaxSpeedStr +
17086  "km/h; Power " + PowerStr + "kW" + '\n' + "Mass " + MassStr + "Te; Brakes " + MaxBrakeStr + "Te" + '\n' + SpecialStr + Status + '\n' + "Next: " +
17087  NextStopStr;
17088  }
17089  else
17090  {
17091  TrainStatusFloat = HeadCode + ": " + Train.TrainDataEntryPtr->Description + ServiceReferenceInfo + '\n' + "Maximum train speed " + MaxSpeedStr +
17092  "km/h; Power " + PowerStr + "kW" + '\n' + "Mass " + MassStr + "Te; Brakes " + MaxBrakeStr + "Te" + '\n' + SpecialStr + Status + ": " +
17093  CurrSpeedStr.FormatFloat(FormatNoDPStr, CurrSpeed) + "km/h" + '\n' + "Next: " + NextStopStr;
17094  }
17095  Utilities->CallLogPop(2263);
17096  return(TrainStatusFloat);
17097 }
17098 
17099 // ---------------------------------------------------------------------------
17100 
17101 void TInterface::FlashingGraphics(int Caller, TDateTime Now)
17102 // following section checks to see if GapFlashFlag set & flashes the Gap graphics if so
17103 // Gap flashing is cancelled on any mousedown event
17104 
17105 {
17106  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FlashingGraphics");
17107 // deal with flashing GapFlash graphics (only in basic mode so no need to check for trains)
17109  {
17110  if(WarningFlash)
17111  {
17112  Track->GapFlashGreen->PlotOverlay(4, Display); // only plotted if PlotOverlay reset
17114  }
17115  else
17116  {
17117  Track->GapFlashGreen->PlotOriginal(17, Display); // only plotted if PlotOverlay set
17119  }
17120  }
17122  {
17123  if(WarningFlash)
17124  {
17129  Display->Update();
17130  }
17131  else
17132  {
17137  Display->Update();
17138  }
17139  }
17140 // deal with gap setting - added at v2.6.1 to make location easier
17142  {
17144  }
17146  {
17147  Display->Ellipse(2, Track->GetGapHLoc() * 16, Track->GetGapVLoc() * 16, clB0G0R5);
17148  }
17150  {
17152  }
17154  {
17155  Display->Ellipse(3, Track->GetGapHLoc() * 16, Track->GetGapVLoc() * 16, clB5G5R5);
17156  }
17157 // deal with other flashing graphics
17159  {
17160  if((Now - RouteFlashStartTime) < TDateTime(RouteFlashDuration / 86400))
17161  {
17162  // cancel if train is moving & arrives on any part of flashing route
17164  {
17165  Track->RouteFlashFlag = false;
17167  ClearandRebuildRailway(18); // because using ConstructRoute->RouteFlash.PlotOriginal() can plot wrong point fillet as well as
17168  // original (if proposed route would change point). With this can dispense with ConstructRoute->RouteFlash.PlotOriginal()
17169  Utilities->CallLogPop(75);
17170  return;
17171  }
17172  InfoPanel->Visible = true;
17173  if(Level2OperMode == PreStart)
17174  {
17175  InfoPanel->Caption = "PRE-START: Route setting in progress";
17176  }
17177  else
17178  {
17179  InfoPanel->Caption = "OPERATING: Route setting in progress";
17180  }
17181  if(WarningFlash)
17182  {
17184  }
17185  else
17186  {
17188  }
17189  }
17190  else
17191  {
17192 // ConstructRoute->RouteFlash.PlotOriginal(); don't need with clearand....
17193 // stop clock while converting route as can take several seconds
17194  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
17196  if(PreferredRouteFlag)
17197  {
17199  }
17200  else
17201  {
17203  }
17204  ConstructRoute->ClearRoute(); // clear it immediately after use so as not to clutter the errorlog
17205  TrainController->BaseTime = TDateTime::CurrentDateTime();
17207  Track->RouteFlashFlag = false;
17209  ClearandRebuildRailway(19); // if drop this ensure replot trains after replot routes else route will overwrite a train
17210  }
17211  }
17212  if(Track->RouteFlashFlag && Display->ZoomOutFlag) // must have entered RouteFlash from normal screen so button states stored
17213  // dropped ZoomOutButton when route or point flashing, but leave this section in in case need to reinstate
17214  // no need to call Clearand... as that is called when revert to normal mode
17215  {
17216  if((Now - RouteFlashStartTime) >= TDateTime(RouteFlashDuration / 86400))
17217  {
17218  Track->RouteFlashFlag = false;
17219  if(PreferredRouteFlag)
17220  {
17222  }
17223  else
17224  {
17226  }
17227  ConstructRoute->ClearRoute(); // clear it immediately after use so as not to clutter the errorlog
17228  }
17229  }
17231  {
17232  if((Now - PointFlashStartTime) < TDateTime((PointsFlashDuration) / 86400))
17233  {
17234  // cancel if train is present on or enters a flashing point, either selected or diverging
17236  {
17238  Track->PointFlashFlag = false;
17240  Utilities->CallLogPop(76);
17241  return;
17242  }
17244  {
17246  Track->PointFlashFlag = false;
17248  Utilities->CallLogPop(77);
17249  return;
17250  }
17251  if(WarningFlash)
17252  {
17255  }
17256  else
17257  {
17259  }
17260  }
17261  else
17262  {
17267  {
17271  }
17273  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
17274  Track->PointFlashFlag = false;
17276  }
17277  }
17279  // dropped ZoomOutButton when point flashing but leave this section in in case need to reinstate
17280  {
17281  if((Now - PointFlashStartTime) < TDateTime((PointsFlashDuration) / 86400))
17282  {
17286  {
17289  }
17290  Track->PointFlashFlag = false;
17292  }
17293  }
17294 // deal with changing level crossings
17295  if(!Track->ChangingLCVector.empty() && (Level2OperMode != Paused))
17296  {
17297  int H;
17298  int V;
17299 
17300  for(unsigned int x = 0; x < Track->ChangingLCVector.size(); x++)
17301  {
17302  bool Manual = false;
17303  if(Track->ChangingLCVector.at(x).TypeOfRoute == 2) // manual
17304  {
17305  Manual = true;
17306  }
17307  H = Track->ChangingLCVector.at(x).HLoc;
17308  V = Track->ChangingLCVector.at(x).VLoc;
17309  if((Now - Track->ChangingLCVector.at(x).StartTime) < TDateTime((Track->ChangingLCVector.at(x).ChangeDuration) / 86400))
17310  // still flashing
17311  {
17312  if(WarningFlash)
17313  {
17314  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Raising) // closing to trains
17315  {
17316  Track->PlotRaisedLinkedLevelCrossingBarriers(1, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V, Display);
17317 // always plots red when raising
17318  }
17319  else
17320  {
17321  Track->PlotLoweredLinkedLevelCrossingBarriers(0, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
17322  Track->ChangingLCVector.at(x).TypeOfRoute, Display, Manual);
17323  }
17324  }
17325  else
17326  {
17327  Track->PlotLCBaseElementsOnly(2, Track->ChangingLCVector.at(x).BarrierState, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
17328  Track->ChangingLCVector.at(x).TypeOfRoute, Display);
17329  }
17330  }
17331  else
17332  // flashing period finished
17333  {
17334  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Raising)
17335  {
17336  Track->PlotRaisedLinkedLevelCrossingBarriers(2, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V, Display);
17337 // always plot red when fully raised
17338  Track->SetLinkedLevelCrossingBarrierAttributes(4, H, V, 0); // only set attr to 0 when fully raised
17339  // attributes set to 2 when changing state, now reset to 0, no other actions needed
17340  }
17341  else
17342  // barriers lowering
17343  {
17344  Track->PlotLoweredLinkedLevelCrossingBarriers(1, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
17345  Track->ChangingLCVector.at(x).TypeOfRoute, Display, Manual);
17346  Track->SetLinkedLevelCrossingBarrierAttributes(5, H, V, 1); // only set attr to 1 when fully lowered
17347  bool FoundFlag;
17348  int TVPos = Track->GetVectorPositionFromTrackMap(46, H, V, FoundFlag);
17349  if(!FoundFlag)
17350  {
17351  throw Exception("Failed to find a route at LC position HLoc = " + (AnsiString)H + " VLoc = " + (AnsiString)V);
17352  }
17353  int RouteNumber;
17354  AllRoutes->GetRouteTypeAndNumber(24, TVPos, 0, RouteNumber); // use 0 for LinkPos, could be 1 or 0 as only a single track element
17355  // don't need returned value of RouteType
17356  if(RouteNumber > -1) // if train crashed then there won't be a routenumber
17357  {
17358  AllRoutes->GetFixedRouteAt(196, RouteNumber).SetRouteSignals(8);
17359  }
17360  }
17361  }
17362  }
17363  for(int x = Track->ChangingLCVector.size() - 1; x >= 0; x--)
17364  {
17365  // now transfer lowering barrier object from the ChangingLCVector to the BarriersDownVector if lowering, reset the start timer (to time the barrier down period)
17366  // and for either raising or lowering erase the object from the ChangingLCVector
17367  if(!Track->IsLCBarrierFlashingAtHV(0, Track->ChangingLCVector.at(x).HLoc, Track->ChangingLCVector.at(x).VLoc))
17368  {
17369  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Lowering)
17370  {
17371  Track->ChangingLCVector.at(x).StartTime = TrainController->TTClockTime;
17372  Track->ChangingLCVector.at(x).BarrierState = TTrack::Down;
17373  Track->BarriersDownVector.push_back(Track->ChangingLCVector.at(x));
17374  }
17375  Track->ChangingLCVector.erase(Track->ChangingLCVector.begin() + x);
17376  }
17377  }
17378  }
17379  Utilities->CallLogPop(747);
17380 }
17381 
17382 // ---------------------------------------------------------------------------
17383 
17384 void TInterface::SetSaveMenuAndButtons(int Caller)
17385 // set boundary, Home, NewHome, ZoomOut, CallingOn buttons & menu items as appropriate
17386 {
17387  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetSaveMenuAndButtons");
17388 
17389 // set save railway buttons
17390  bool SaveRailwayButtonsFlag = true;
17391 
17392  SaveRailwayTBPButton->Visible = true;
17393  SaveRailwayPDPButton->Visible = true;
17394  SaveSessionButton->Visible = true;
17395  if(Level1Mode == OperMode)
17396  {
17398  {
17399  SaveRailwayButtonsFlag = false;
17400  }
17401  // set PresetAutoSigRoutesButton enabled or not
17402  // enable if PreStart & no routes set
17403  if((Level2OperMode == PreStart) && (AllRoutes->AllRoutesVector.empty()) && !EveryPrefDir->PrefDirVector.empty())//added EveryPrefDir condition at v2.10.0
17404  {
17405  PresetAutoSigRoutesButton->Enabled = true;
17406  }
17407  else
17408  {
17409  PresetAutoSigRoutesButton->Enabled = false;
17410  }
17411  }
17412  else
17413  {
17415  && Track->UserGraphicVector.empty()))
17416  {
17417  SaveRailwayButtonsFlag = false;
17418  }
17419  else if(SavedFileName != "")
17420  {
17421  if((SavedFileName[SavedFileName.Length()] == 'y') || (SavedFileName[SavedFileName.Length()] == 'Y')) // 'rly' file
17422  {
17423  if(!(Track->IsReadyForOperation(false)))
17424  {
17425  SaveRailwayButtonsFlag = false; // can't save under its old name as not now a .rly file
17426  }
17427  }
17428  }
17429  }
17430  if(SaveRailwayButtonsFlag && (Level1Mode == BaseMode))
17431  {
17432  SaveRailwayBaseModeButton->Visible = true;
17433  }
17434  else
17435  {
17436  SaveRailwayBaseModeButton->Visible = false;
17437  }
17438  SaveRailwayTBPButton->Enabled = SaveRailwayButtonsFlag;
17439  SaveRailwayPDPButton->Enabled = SaveRailwayButtonsFlag;
17440  SaveRailwayBaseModeButton->Enabled = SaveRailwayButtonsFlag;
17441  SaveSessionButton->Enabled = SaveRailwayButtonsFlag;
17442 
17443 // set formatted timetable menu item
17444  if(TimetableTitle == "")
17445  {
17446  ExportTTMenuItem->Enabled = false;
17447  }
17448  else
17449  {
17450  ExportTTMenuItem->Enabled = true;
17451  }
17452 // set info menu items
17454  {
17455  FloatingInfoMenu->Enabled = false;
17456  TrackInfoMenuItem->Enabled = false;
17457  TrainInfoMenuItem->Enabled = false;
17458  }
17459  else
17460  {
17461  FloatingInfoMenu->Enabled = true;
17462  TrackInfoMenuItem->Enabled = true;
17463  if(Level1Mode == OperMode)
17464  {
17465  TrainInfoMenuItem->Enabled = true;
17466  }
17467  else
17468  {
17469  TrainInfoMenuItem->Enabled = false;
17470  }
17471  }
17472 // set all bar CallingOnButton operational to begin with - no, causes flickering of button graphics,
17473 // work on internal flags & then set buttons according to final flag values, then graphic won't change unless
17474 // there has been a legitimate change of state since the last access
17475 
17476  bool ZoomFlag = true, HomeFlag = true, NewHomeFlag = true, ScreenLeftFlag = true, ScreenRightFlag = true, ScreenUpFlag = true, ScreenDownFlag = true,
17477  TrackBuildPanelEnabledFlag = true, PrefDirPanelEnabledFlag = true, OperatingPanelEnabledFlag = true, TimetablePanelEnabledFlag = true;
17478 
17479  AnsiString TrackBuildPanelLabelCaptionStr = "Build/modify";
17480  AnsiString PrefDirPanelLabelCaptionStr = "Preferred direction selection";
17481  AnsiString OperatingPanelLabelCaptionStr = "Operation";
17482  AnsiString TimetablePanelLabelCaptionStr = "Timetable editor";
17483 
17484  if(!Display->ZoomOutFlag)
17485  {
17486  // prevent if half a screen or less visible (width = 60, height = 36) [Note HLocMin & Max 1 greater than extreme element]
17488  {
17489  ScreenLeftFlag = false; // 60 - 30
17490  }
17492  {
17493  ScreenRightFlag = false; // 60 - (60 - 30)
17494  }
17496  {
17497  ScreenUpFlag = false; // 36 - 18
17498  }
17500  {
17501  ScreenDownFlag = false; // 36 - (36 - 18)
17502  }
17503  }
17504  else
17505  {
17506  // prevent if less than a quarter of a screen visible (width = 240, height = 144)
17508  {
17509  ScreenLeftFlag = false; // 240 - 60
17510  }
17512  {
17513  ScreenRightFlag = false; // 240 - (240 - 60)
17514  }
17516  {
17517  ScreenUpFlag = false; // 144 - 36
17518  }
17520  {
17521  ScreenDownFlag = false; // 144 - (144 - 36)
17522  }
17523  }
17525  {
17526  ZoomFlag = false;
17527  HomeFlag = false;
17528  NewHomeFlag = false;
17529  ScreenLeftFlag = false;
17530  ScreenRightFlag = false;
17531  ScreenUpFlag = false;
17532  ScreenDownFlag = false;
17533  }
17534  if(Display->ZoomOutFlag)
17535  {
17536 // NewHomeFlag = false;
17537  TrackBuildPanelEnabledFlag = false;
17538  TrackBuildPanelLabelCaptionStr = "Disabled";
17539  PrefDirPanelEnabledFlag = false;
17540  PrefDirPanelLabelCaptionStr = "Disabled";
17541  OperatingPanelEnabledFlag = false;
17542  OperatingPanelLabelCaptionStr = "Disabled";
17543  TimetablePanelEnabledFlag = false;
17544  TimetablePanelLabelCaptionStr = "Disabled";
17545  }
17546  if(Level1Mode == OperMode)
17547  {
17548  if(Track->RouteFlashFlag || Track->PointFlashFlag || TTClockAdjPanel->Visible == true || TTClockAdjustWarningPanel->Visible == true)
17549  // TTClockAdjPanel added for v2.4.2 to keep it disabled after Clock2Stopped dropped
17550  {
17551  MTBFEditBox->Enabled = false;
17552  OperatingPanelEnabledFlag = false;
17553  OperatingPanelLabelCaptionStr = "Disabled";
17554  ZoomFlag = false;
17555  HomeFlag = false;
17556  NewHomeFlag = false;
17557  ScreenLeftFlag = false;
17558  ScreenRightFlag = false;
17559  ScreenUpFlag = false;
17560  ScreenDownFlag = false;
17561  SaveOperatingImageMenuItem->Enabled = false;
17562  }
17563  else
17564  {
17565  MTBFEditBox->Enabled = true;
17566  SaveOperatingImageMenuItem->Enabled = true;
17567  }
17568  }
17569  if(LocationNameTextBox->Visible)
17570  {
17571  ZoomFlag = false;
17572  HomeFlag = false;
17573  NewHomeFlag = false;
17574  ScreenLeftFlag = false;
17575  ScreenRightFlag = false;
17576  ScreenUpFlag = false;
17577  ScreenDownFlag = false;
17578  }
17579  if(TextBox->Visible) // added at v1.3.0 to prevent screen moving when movement keys pressed during text entry
17580  {
17581  ZoomFlag = false;
17582  HomeFlag = false;
17583  NewHomeFlag = false;
17584  ScreenLeftFlag = false;
17585  ScreenRightFlag = false;
17586  ScreenUpFlag = false;
17587  ScreenDownFlag = false;
17588  }
17589  if((Level1Mode == TimetableMode) && (TimetableEditPanel->Visible))
17590  // added at v1.3.0 to prevent screen moving when movement keys pressed during timetable compilation (allowed if TT hidden)
17591  {
17592  ZoomFlag = false;
17593  HomeFlag = false;
17594  NewHomeFlag = false;
17595  ScreenLeftFlag = false;
17596  ScreenRightFlag = false;
17597  ScreenUpFlag = false;
17598  ScreenDownFlag = false;
17599  }
17602  {
17603  ZoomFlag = false;
17604  }
17605  if(ZoomFlag)
17606  {
17607  ZoomButton->Enabled = true;
17608  }
17609  else
17610  {
17611  ZoomButton->Enabled = false;
17612  }
17613  if(HomeFlag)
17614  {
17615  HomeButton->Enabled = true;
17616  }
17617  else
17618  {
17619  HomeButton->Enabled = false;
17620  }
17621  if(NewHomeFlag)
17622  {
17623  NewHomeButton->Enabled = true;
17624  }
17625  else
17626  {
17627  NewHomeButton->Enabled = false;
17628  }
17629  if(ScreenLeftFlag)
17630  {
17631  ScreenLeftButton->Enabled = true;
17632  }
17633  else
17634  {
17635  ScreenLeftButton->Enabled = false;
17636  }
17637  if(ScreenRightFlag)
17638  {
17639  ScreenRightButton->Enabled = true;
17640  }
17641  else
17642  {
17643  ScreenRightButton->Enabled = false;
17644  }
17645  if(ScreenUpFlag)
17646  {
17647  ScreenUpButton->Enabled = true;
17648  }
17649  else
17650  {
17651  ScreenUpButton->Enabled = false;
17652  }
17653  if(ScreenDownFlag)
17654  {
17655  ScreenDownButton->Enabled = true;
17656  }
17657  else
17658  {
17659  ScreenDownButton->Enabled = false;
17660  }
17661  if(OperatingPanelEnabledFlag)
17662  {
17663  OperatingPanel->Enabled = true;
17664  }
17665  else
17666  {
17667  OperatingPanel->Enabled = false;
17668  }
17669  if(TrackBuildPanelEnabledFlag)
17670  {
17671  TrackBuildPanel->Enabled = true;
17672  }
17673  else
17674  {
17675  TrackBuildPanel->Enabled = false;
17676  }
17677  if(PrefDirPanelEnabledFlag)
17678  {
17679  PrefDirPanel->Enabled = true;
17680  }
17681  else
17682  {
17683  PrefDirPanel->Enabled = false;
17684  }
17685  if(TimetablePanelEnabledFlag)
17686  {
17687  TimetablePanel->Enabled = true;
17688  }
17689  else
17690  {
17691  TimetablePanel->Enabled = false;
17692  }
17693  TrackBuildPanelLabel->Caption = TrackBuildPanelLabelCaptionStr;
17694  PrefDirPanelLabel->Caption = PrefDirPanelLabelCaptionStr;
17695  OperatingPanelLabel->Caption = OperatingPanelLabelCaptionStr;
17696  TimetablePanelLabel->Caption = TimetablePanelLabelCaptionStr;
17697 
17698 // check if any CallingOnFlags set & set button accordingly
17699  if(Display->ZoomOutFlag)
17700  {
17701  CallingOnButton->Enabled = false;
17702  CallingOnButton->Down = false;
17703  }
17704  else
17705  {
17706  if(Level2OperMode == Operating)
17707  {
17708  bool CallOnValid = false;
17709  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
17710  {
17712  {
17713  CallingOnButton->Enabled = true;
17714  CallOnValid = true;
17715  }
17716  }
17717  if(!CallOnValid)
17718  {
17719  CallingOnButton->Enabled = false;
17720  CallingOnButton->Down = false;
17721  }
17722  }
17723  else
17724  {
17725  CallingOnButton->Enabled = false;
17726  CallingOnButton->Down = false;
17727  }
17728  }
17729  Utilities->CallLogPop(970);
17730 }
17731 
17732 // ---------------------------------------------------------------------------
17733 
17734 void TInterface::ErrorLog(int Caller, AnsiString Message)
17735 {
17736 // create an error file for diagnostic purposes called on detection of a runtime error
17737 
17738 // Note: For faults in ClockTimer2, after the catch block in ClockTimer2 which calls this function, execution continues from where
17739 // ClockTimer2 was called, so the Utilities->Clock2Stopped flag is cleared and the whole sequence repeats itself, including the fault, until
17740 // the user presses the Exit button. Note also that Utilities->CallLogPop, called when ClockTimer (not ClockTimer2) returns, pops the error
17741 // message off the back of the Utilities->CallLog, not the ClockTimer call. Hence entries keep stacking up, including the push_front entry
17742 // but not the push_back error entry, and when finally printed there is a whole series of entries for the one fault, the number
17743 // depending on the time taken to press Exit.
17744 // Hence introduce an ErrorLogCalledFlag, set to true on first call, and preventing further calls thereafter.
17745 
17746  if(ErrorLogCalledFlag)
17747  {
17748  return;
17749  }
17750  ErrorLogCalledFlag = true;
17751  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + "," + Message);
17752  Utilities->CallLog.push_front("Version: " + ProgramVersion + "; Time and date: " + Utilities->DateTimeStamp());
17753  SaveErrorFile();
17754  if((TempTTFileName != "") && FileExists(TempTTFileName))
17755  {
17756  DeleteFile(TempTTFileName);
17757  }
17758  Display->GetImage()->Visible = false;
17759  PerformancePanel->Visible = false;
17760  OperatorActionPanel->Visible = false; // new v2.2.0
17761  TrackBuildPanel->Visible = false;
17762  TrackElementPanel->Visible = false;
17763  LocationNameTextBox->Visible = false;
17764  TextBox->Visible = false;
17765  TrackLengthPanel->Visible = false;
17766  InfoPanel->Visible = false;
17767  PrefDirPanel->Visible = false;
17768  TimetablePanel->Visible = false;
17769  TimetableEditPanel->Visible = false;
17770  TrainController->TTEditPanelVisible = false; // added at v2.6.0 for two location message
17771  OperatingPanel->Visible = false;
17772  FloatingPanel->Visible = false;
17773  ModeMenu->Enabled = false;
17774  SigImagePanel->Visible = false; // new at v2.3.0
17775  FileMenu->Enabled = false;
17776  EditMenu->Enabled = false;
17777  FloatingInfoMenu->Enabled = false;
17778  HelpMenu->Enabled = false;
17779 // SaveHeaderMenu1->Enabled = false;
17780  ScreenLeftButton->Visible = false;
17781  ScreenRightButton->Visible = false;
17782  ScreenUpButton->Visible = false;
17783  ScreenDownButton->Visible = false;
17784  HomeButton->Visible = false;
17785  NewHomeButton->Visible = false;
17786  ZoomButton->Visible = false;
17787  PrefDirKey->Visible = false;
17788  DistanceKey->Visible = false;
17789  RecoverClipboardMessageSent = true; // to stop paste message being given if recover clipboard error
17790  OutputLog1->Caption = "";
17791  OutputLog2->Caption = "";
17792  OutputLog3->Caption = "";
17793  OutputLog4->Caption = "";
17794  OutputLog5->Caption = "";
17795  OutputLog6->Caption = "";
17796  OutputLog7->Caption = "";
17797  OutputLog8->Caption = "";
17798  OutputLog9->Caption = "";
17799  OutputLog10->Caption = "";
17800  if(Caller == 113)
17801  {
17802  ErrorMessageStoreImage->Visible = true;
17803  }
17804  else
17805  {
17806  ErrorMessage->Visible = true;
17807  }
17808  ErrorButton->Visible = true;
17809  Screen->Cursor = TCursor(-2); // Arrow; - in case was an hourglass
17810 // No need for Utilities->CallLogPop as the call log deque has already been written to file & the next action
17811 // is to close the program when the exit button is pressed
17812 }
17813 
17814 // ---------------------------------------------------------------------------
17815 
17817 // not used from v2.2.0 as now allow floating panel & label to overlie performance panel
17818 {
17819  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPerformancePanelObscuringFloatingLabel");
17820  if(FloatingPanel->Visible == false)
17821  {
17822  Utilities->CallLogPop(1205);
17823  return(false);
17824  }
17825 // pptop >= flbot, ppbot <= fltop, ppleft >= flright, ppright <= flleft
17826  if((PerformancePanel->Top >= (FloatingPanel->Top + FloatingPanel->Height)) || ((PerformancePanel->Top + PerformancePanel->Height) <= FloatingPanel->Top) ||
17827  (PerformancePanel->Left >= (FloatingPanel->Left + FloatingPanel->Width)) || ((PerformancePanel->Left + PerformancePanel->Width) <= FloatingPanel->Left))
17828  {
17829  Utilities->CallLogPop(1206);
17830  return(false);
17831  }
17832  else
17833  {
17834  Utilities->CallLogPop(1207);
17835  return(true);
17836  }
17837 }
17838 // ---------------------------------------------------------------------------
17839 
17840 void TInterface::SetCaption(int Caller)
17841 {
17842 /*
17843  NamedRailway; RlyFile; NamedTimetable
17844  n x x "New railway under development";
17845  y n x RailwayTitle + ": under development";
17846  y y n RailwayTitle + ": no timetable loaded";
17847  y y y RailwayTitle + ", " + TimetableTitle;
17848 */
17849 
17850  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetCaption");
17851  if(RailwayTitle == "")
17852  {
17853  Caption = "Railway: New railway under development";
17854  }
17855  else if(!RlyFile)
17856  {
17857  Caption = "Railway: " + RailwayTitle + " under development";
17858  }
17859 // else if(TimetableTitle == "") Caption = "Railway: " + RailwayTitle + "; Timetable: none loaded";
17860  else if(TimetableTitle == "")
17861  {
17862  Caption = "Railway: " + RailwayTitle; // changed at v2.1.0, no need to mention TT if none loaded
17863  }
17864  else
17865  {
17866  Caption = "Railway: " + RailwayTitle + "; Timetable: " + TimetableTitle;
17867  }
17868  session_api_->dump(); // update session INI file //added at v2.10.0
17869  Utilities->CallLogPop(1208);
17870 }
17871 
17872 // ---------------------------------------------------------------------------
17873 
17874 void TInterface::ResetAll(int Caller)
17875 {
17876  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAll");
17877  LastNonCtrlOrShiftKeyDown = -1; // added at v2.4.2 to no key down
17879  Track->GapFlashRedPosition = -1;
17880  Track->GapFlashFlag = false;
17881  Track->RouteFlashFlag = false;
17882  Track->PointFlashFlag = false;
17884  AutoSigsFlag = false;
17885  PreventGapOffsetResetting = false;
17886 
17887  Utilities->Clock2Stopped = false;
17888  TTClockSpeed = 1;
17889  TTClockSpeedLabel->Caption = "x1";
17890  Track->SetTrackFinished(false);
17892  CurrentSpeedButton = 0; // not assigned yet
17894  StartX = 0;
17895  StartY = 0;
17896  mbLeftDown = false;
17898  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
17900  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect");
17902  WarningFlashCount = 0;
17903 
17904  Level1Mode = BaseMode;
17905  SetLevel1Mode(26);
17906  RouteMode = None;
17907  PreferredRoute = true; // default starting conditions
17908  ConsecSignalsRoute = true; // default starting conditions
17909  DevelopmentPanel->Visible = false;
17910 
17911  MainScreen->Canvas->CopyMode = cmSrcCopy;
17912  FloatingPanel->Visible = false;
17913  OverallDistance = 0;
17914  OverallSpeedLimit = -1;
17915  AllRoutes->RouteTruncateFlag = false;
17916  CallingOnButton->Down = false;
17917  Display->ZoomOutFlag = false;
17918  ScreenGridFlag = false;
17919  InfoCaptionStore = "";
17920  ErrorLogCalledFlag = false;
17921  ErrorMessage->Visible = false;
17922  ErrorMessageStoreImage->Visible = false;
17923  TempCursorSet = false;
17924  TempCursor = TCursor(-2); // Arrow
17925  WholeRailwayMoving = false; // new at v2.1.0
17926 
17927  TrainController->TTClockTime = TDateTime(0); // default setting
17928  TTClockAdjPanel->Visible = false;
17930  ConflictPanel->Visible = false;
17931  SelectedTrainID = -1;
17932  SetTrackBuildImages(11);
17933 // TrackInfoOnOffMenuItem->Caption = "Show"; dropped these here at v1.2.0 so don't reset when load a session file
17934 // TrainStatusInfoOnOffMenuItem->Caption = "Show Status";
17935 // TrainTTInfoOnOffMenuItem->Caption = "Show Timetable";
17936  Track->CalcHLocMinEtc(8);
17937  FileChangedFlag = false;
17938  RlyFile = false;
17939  SaveSessionFlag = false;
17940  LoadSessionFlag = false;
17941  SelectionValid = false;
17942  TimetableChangedFlag = false;
17943  SavedFileName = "";
17944  RailwayTitle = "";
17945  TimetableTitle = "";
17946  SetCaption(1);
17947  CreateEditTTFileName = ""; // set to null to allow a check during error file saving, if not null save the tt being edited to the file
17948  // added for Beta v0.2b
17949  CreateEditTTTitle = ""; // as above
17950  AllRoutes->NextRouteID = 0;
17951  TTrain::NextTrainID = 0; // reset to 0 whenever enter operating mode
17952  TFont *TempFont = new TFont; // if try to alter MainScreen->Canvas->Font directly it won't change the style for some reason
17953 
17954  TempFont->Style.Clear();
17955  TempFont->Name = "MS Sans Serif"; // reset font, else stays set to last displayed text font
17956  TempFont->Size = 10;
17957  TempFont->Color = clB0G0R0;
17958  TempFont->Charset = (TFontCharset)(0);
17959  MainScreen->Canvas->Font->Assign(TempFont);
17960  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
17961  PerformancePanel->Left = MainScreen->Left;
17962  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height; // new v2.2.0
17963  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width;
17964  ; // new v2.2.0
17965  // ScreenRightButton->Left = MainScreen->Width + MainScreen->Left; //Button values changed at v2.1.0 to allow for screen resizing
17966  // ScreenLeftButton->Left = ScreenRightButton->Left;
17967  // ScreenUpButton->Left = ScreenRightButton->Left;
17968  // ScreenDownButton->Left = ScreenRightButton->Left;
17969  // HomeButton->Left = ScreenRightButton->Left;
17970  // NewHomeButton->Left = ScreenRightButton->Left;
17971  // ZoomButton->Left = ScreenRightButton->Left;
17972  DevelopmentPanel->Top = MainScreen->Top + MainScreen->Height - DevelopmentPanel->Height;
17973  DevelopmentPanel->Left = MainScreen->Left + MainScreen->Width - DevelopmentPanel->Width;
17974  ; // new v2.2.0
17975 
17976  delete TempFont;
17977  CtrlKey = false;
17978  ShiftKey = false;
17979  ClipboardChecked = false;
17980  session_api_->dump(); // update session INI file //added at v2.10.0
17981  Utilities->CallLogPop(1209);
17982 }
17983 
17984 // ---------------------------------------------------------------------------
17985 
17986 void TInterface::SetTrackBuildImages(int Caller)
17987 {
17988  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrackBuildImages,");
17989  if((Level1Mode == OperMode) || RlyFile)
17990  {
17991  TrackLinkedImage->Visible = false;
17992  TrackNotLinkedImage->Visible = false;
17993  GapsSetImage->Visible = false;
17994  GapsNotSetImage->Visible = false;
17995  LocationNamesSetImage->Visible = false;
17996  LocationNamesNotSetImage->Visible = false;
17997  Utilities->CallLogPop(1114);
17998  return;
17999  }
18000  else
18001  {
18002  if(!Track->NoActiveTrack(9))
18003  {
18004  if(Track->IsTrackFinished())
18005  {
18006  TrackLinkedImage->Visible = true;
18007  TrackNotLinkedImage->Visible = false;
18008  }
18009  else
18010  {
18011  TrackNotLinkedImage->Visible = true;
18012  TrackLinkedImage->Visible = false;
18013  }
18014  }
18015  else
18016  {
18017  TrackLinkedImage->Visible = false;
18018  TrackNotLinkedImage->Visible = false;
18019  }
18020  if(!Track->NoGaps(1))
18021  {
18022  if(Track->GapsUnset(6))
18023  {
18024  GapsNotSetImage->Visible = true;
18025  GapsSetImage->Visible = false;
18026  }
18027  else
18028  {
18029  GapsNotSetImage->Visible = false;
18030  GapsSetImage->Visible = true;
18031  }
18032  }
18033  else
18034  {
18035  GapsNotSetImage->Visible = false;
18036  GapsSetImage->Visible = false;
18037  }
18039  {
18040  if(Track->LocationsNotNamed(0))
18041  {
18042  LocationNamesSetImage->Visible = false;
18043  LocationNamesNotSetImage->Visible = true;
18044  }
18045  else
18046  {
18047  LocationNamesSetImage->Visible = true;
18048  LocationNamesNotSetImage->Visible = false;
18049  }
18050  }
18051  else
18052  {
18053  LocationNamesSetImage->Visible = false;
18054  LocationNamesNotSetImage->Visible = false;
18055  }
18056  }
18057  Utilities->CallLogPop(1113);
18058 }
18059 
18060 // ---------------------------------------------------------------------------
18061 
18062 void TInterface::ResetChangedFileDataAndCaption(int Caller, bool NonPrefDirChangesMade)
18063 {
18064  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetChangedFileDataAndCaption");
18065  FileChangedFlag = true;
18066  if(NonPrefDirChangesMade)
18067  {
18068  if(RlyFile) // i.e. was a Railway file but major changes made so class as a new railway
18069  {
18070  RailwayTitle = "";
18071  TimetableTitle = "";
18072  SavedFileName = "";
18073  RlyFile = false;
18074  }
18075  TimetableTitle = ""; // should have been reset already during user mode change but include here also
18076  SetTrackBuildImages(15);
18077  }
18078  session_api_->dump(); // update session INI file //added at v2.10.0
18079  SetCaption(2);
18080  Utilities->CallLogPop(1210);
18081 }
18082 
18083 // ---------------------------------------------------------------------------
18084 
18085 void TInterface::SaveSession(int Caller)
18086 {
18087  // ExcessLCDownMins saved as string after ***Interface*** see below
18088  try
18089  {
18090  TrainController->LogEvent("SaveSession");
18091  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSession");
18092  AnsiString CurrentDateTimeStr = "", TimetableTimeStr = "", SessionFileStr = "";
18093  Screen->Cursor = TCursor(-11); // Hourglass;
18094  CurrentDateTimeStr = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
18095  // avoid characters in filename:= / \ : * ? " < > |
18096  TimetableTimeStr = Utilities->Format96HHMMSS(TrainController->TTClockTime);
18097  TimetableTimeStr = TimetableTimeStr.SubString(1, 2) + '.' + TimetableTimeStr.SubString(4, 2) + '.' + TimetableTimeStr.SubString(7, 2);
18098 // SessionFileStr = CurDir + "\\" + SESSION_DIR_NAME + "\\Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
18099 // "; " + TimetableTitle + ".ssn";
18100  SessionFileStr = LoadSessionDialog->InitialDir + "\\Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
18101  "; " + TimetableTitle + ".ssn";
18102  std::ofstream SessionFile(SessionFileStr.c_str());
18103  if(!(SessionFile.fail()))
18104  {
18105  Utilities->SaveFileString(SessionFile, ProgramVersion + ": ***Interface***" + FloatToStr(TrainController->ExcessLCDownMins));
18106 // added ExcessLC... at v2.2.0 as omitted earlier
18107  SaveInterface(0, SessionFile);
18108  // save track elements
18109  Utilities->SaveFileString(SessionFile, "***Track***");
18110  if(Track->UserGraphicVector.empty())
18111  {
18112  Track->SaveTrack(4, SessionFile, false); // false for no graphics (**Active elements** saved as marker)
18113  }
18114  else
18115  {
18116  Track->SaveTrack(11, SessionFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
18117  }
18118  // save text elements
18119  Utilities->SaveFileString(SessionFile, "***Text***");
18120  TextHandler->SaveText(2, SessionFile);
18121  // save PrefDir elements
18122  Utilities->SaveFileString(SessionFile, "***PrefDirs***");
18123  EveryPrefDir->SavePrefDirVector(2, SessionFile);
18124  if(!Track->UserGraphicVector.empty())
18125  {
18126  // save user graphics
18127  Track->SaveUserGraphics(2, SessionFile);
18128  }
18129  // save routes
18130  Utilities->SaveFileString(SessionFile, "***Routes***");
18131  AllRoutes->SaveRoutes(0, SessionFile);
18132  // save LockedRoutes
18133  Utilities->SaveFileString(SessionFile, "***Locked routes***");
18134  TrainController->SaveSessionLockedRoutes(0, SessionFile);
18135  // save ContinuationAutoSigEntries
18136  Utilities->SaveFileString(SessionFile, "***ContinuationAutoSigEntries***");
18138  // save BarriersDownVector
18139  Utilities->SaveFileString(SessionFile, "***BarriersDownVector***");
18140  Track->SaveSessionBarriersDownVector(0, SessionFile);
18141  // save timetable
18142  Utilities->SaveFileString(SessionFile, "***Timetable***");
18143  if(!(SaveTimetableToSessionFile(0, SessionFile, SessionFileStr))) //includes the timetable itself + TrainOperatingData
18144  {
18145  SessionFile.close();
18146  DeleteFile(SessionFileStr);
18147  Screen->Cursor = TCursor(-2); // Arrow;
18148  TrainController->StopTTClockMessage(3, "Error saving file, unable to save session");
18149  Utilities->CallLogPop(1150);
18150  return;
18151  }
18152  // save TimetableClock
18153  Utilities->SaveFileString(SessionFile, "***TimetableClock***");
18154  Utilities->SaveFileDouble(SessionFile, double(TrainController->TTClockTime));
18155 
18156  // save trains
18157  Utilities->SaveFileString(SessionFile, "***Trains***");
18158  TrainController->SaveSessionTrains(0, SessionFile);
18159  // save performance file
18160  Utilities->SaveFileString(SessionFile, "***Performance file***");
18161  SavePerformanceFile(0, SessionFile);
18162  Utilities->SaveFileString(SessionFile, "***End of performance file***");
18163 
18164 // addition at v2.4.0 to save TrainController->AvHoursIntValue + any future additions
18165  Utilities->SaveFileString(SessionFile, "***Additions after v2.3.1***");
18168  Utilities->SaveFileString(SessionFile, "***Failed Trains***");
18169  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
18170  {
18172  {
18175  }
18176  }
18177  Utilities->SaveFileInt(SessionFile, -1); // marker for end of failed trains
18178  Utilities->SaveFileString(SessionFile, "End of file at v2.4.0");
18179 // end of v2.4.0 addition
18180 
18181 // added at v2.7.0
18182  Utilities->SaveFileBool(SessionFile, ConsecSignalsRoute);
18183  Utilities->SaveFileString(SessionFile, "End of file at v2.7.0");
18184 // end of v2.7.0 addition
18185 
18186 // added at v2.9.1
18190  Utilities->SaveFileDouble(SessionFile, double(TrainController->TotEarlyExitMins));
18191  Utilities->SaveFileDouble(SessionFile, double(TrainController->TotLateExitMins));
18192  Utilities->SaveFileString(SessionFile, "End of file at v2.9.1"); //changed from '2.9.0' at v2.9.2
18193 // end of v2.9.1 additions
18194 
18195  SessionFile.close();
18196  TrainController->StopTTClockMessage(4, "Session saved: Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " +
18197  RailwayTitle + "; " + TimetableTitle + ".ssn");
18199 // to restore the ability to reselect Ctrl S after a save (FormKeyUp doesn't work because the Interface form doesn't have focus)
18200  }
18201  else
18202  {
18203  TrainController->StopTTClockMessage(5, "Session file failed to open - reason not known, session unable to be saved.");
18204  }
18206  Screen->Cursor = TCursor(-2); // Arrow
18207  Utilities->CallLogPop(1141);
18208  }
18209  catch(const Exception &e)
18210  {
18211  ErrorLog(40, e.Message);
18212  }
18213 }
18214 
18215 // ---------------------------------------------------------------------------
18216 
18217 void TInterface::LoadSession(int Caller)
18218 // always loads in 'Paused' or 'PreStart' mode
18219 {
18220 // remember to load the timetable clock
18221 // no routes in build
18222 // prob need to set 'OperMode' then 'Paused', ensure have all info needed for these
18223 // set buttons enabled to correspond to flags on reloading. If no PrefDirs then disable all route buttons
18224 // set RlyFile true
18225  try
18226  {
18227  TrainController->LogEvent("LoadSession");
18228  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadSession");
18229  if(!ClearEverything(4))
18230  {
18231  Utilities->CallLogPop(1145);
18232  return;
18233  }
18234  LoadSessionDialog->Filter = "Session file (*.ssn)|*.ssn";
18235  if(LoadSessionDialog->Execute())
18236  {
18237  if(LoadSessionDialog->InitialDir != TPath::GetDirectoryName(LoadSessionDialog->FileName)) // new at v2.6.0 to retain a new directory
18238  {
18239  LoadSessionDialog->InitialDir = TPath::GetDirectoryName(LoadSessionDialog->FileName);
18240  }
18241  TrainController->LogEvent("LoadSession " + LoadSessionDialog->FileName);
18242  Screen->Cursor = TCursor(-11); // Hourglass;
18243  if(SessionFileIntegrityCheck(0, AnsiString(LoadSessionDialog->FileName).c_str()))
18244  // if(true)
18245  {
18246  std::ifstream SessionFile(AnsiString(LoadSessionDialog->FileName).c_str());
18247  if(!(SessionFile.fail()))
18248  {
18249  TrainController->AvHoursIntValue = 0; // initial value set at v2.4.0 in case not changed later
18250  TrainController->MTBFHours = 0; // initial value set at v2.4.0 in case not changed later
18251  AnsiString TempString = Utilities->LoadFileString(SessionFile);
18252 // "version + : ***Interface***" + at v2.2.0 ExcessLCDownMins (omitted earlier)
18253 
18254  int LastCharBeforeFloat = TempString.LastDelimiter('*'); // added at v2.2.0
18255  if((LastCharBeforeFloat == 0) || (LastCharBeforeFloat == TempString.Length()))
18256  // can't find it or no value for Excess LCDownMins, either way count as zero
18257  {
18259  }
18260  else
18261  {
18262  AnsiString FloatStr = TempString.SubString(LastCharBeforeFloat + 1, TempString.Length() - LastCharBeforeFloat);
18263  if(!Utilities->CheckStringDouble(FloatStr)) // returns false for empty string or invalid double
18264  {
18266  }
18267  else
18268  {
18269  TrainController->ExcessLCDownMins = FloatStr.ToDouble();
18270  }
18271  } // end of v2.2.0 * v2.4.0 additions
18272 
18273  LoadInterface(0, SessionFile);
18274  int TempDisplayOffsetH = Display->DisplayOffsetH; // stored as they are zeroed when track loaded
18275  int TempDisplayOffsetV = Display->DisplayOffsetV;
18276  int TempDisplayOffsetHHome = Display->DisplayOffsetHHome;
18277  int TempDisplayOffsetVHome = Display->DisplayOffsetVHome;
18278  bool GraphicsFollow = false;
18279  // load track elements
18280  TempString = Utilities->LoadFileString(SessionFile); // ***Track***"
18281  Track->LoadTrack(4, SessionFile, GraphicsFollow);
18282  // load text elements
18283  TempString = Utilities->LoadFileString(SessionFile); // ***Text***"
18284  TextHandler->LoadText(1, SessionFile);
18285  // load PrefDir elements
18286  TempString = Utilities->LoadFileString(SessionFile); // "***PrefDirs***"
18287  EveryPrefDir->LoadPrefDir(1, SessionFile);
18288  if(GraphicsFollow)
18289  {
18290  Track->LoadGraphics(1, SessionFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME); // include path to Graphics folder);
18291  }
18293  {
18294  SessionFile.close();
18295  Screen->Cursor = TCursor(-2); // Arrow;
18296  ShowMessage("Corruption in preferred direction section of the session file, session can't be loaded");
18297  Utilities->CallLogPop(1438);
18298  return;
18299  }
18300  // load routes
18301  TempString = Utilities->LoadFileString(SessionFile); // "***Routes***"
18302  if(!AllRoutes->LoadRoutes(0, SessionFile))
18303  {
18304  SessionFile.close();
18305  Screen->Cursor = TCursor(-2); // Arrow;
18306  ShowMessage("Corruption in route section of the session file, session can't be loaded");
18307  Utilities->CallLogPop(1439);
18308  return;
18309  }
18310  // load LockedRoutes
18311  TempString = Utilities->LoadFileString(SessionFile); // "***Locked routes***"
18312  TrainController->LoadSessionLockedRoutes(0, SessionFile);
18313  // load ContinuationAutoSigEntries
18314  TempString = Utilities->LoadFileString(SessionFile); // "***ContinuationAutoSigEntries***"
18316  // load BarriersDownVector if present, but ensure backwards compatibility with earlier files
18317  TempString = Utilities->LoadFileString(SessionFile); // "***BarriersDownVector***" or "***Timetable***"
18318  if(TempString == "***BarriersDownVector***")
18319  {
18320  Track->LoadBarriersDownVector(0, SessionFile);
18321  TempString = Utilities->LoadFileString(SessionFile); // "***Timetable***"
18322  }
18323  // load timetable (marker "***Timetable***" already loaded)
18324  if(!(LoadTimetableFromSessionFile(0, SessionFile)))
18325  {
18326  SessionFile.close();
18327  Screen->Cursor = TCursor(-2); // Arrow;
18328  ShowMessage("Unable to load timetable section of the session file, session can't be loaded");
18329  Utilities->CallLogPop(1151);
18330  return;
18331  }
18332  // TimetableTitle should be loaded at this stage - check
18333  if(TimetableTitle == "")
18334  {
18335  SessionFile.close();
18336  Screen->Cursor = TCursor(-2); // Arrow;
18337  throw Exception("TimetableTitle null in LoadSession");
18338  }
18339  // load timetable clock
18340  TempString = Utilities->LoadFileString(SessionFile); // ***TimetableClock***
18341  TrainController->RestartTime = TDateTime(Utilities->LoadFileDouble(SessionFile)); // ClockTime set in RestartSessionOperMode;
18342  // load trains
18343  TempString = Utilities->LoadFileString(SessionFile); // ***Trains***
18344  TrainController->LoadSessionTrains(0, SessionFile);
18345  // load performance file + populate the performance log
18346  TempString = Utilities->LoadFileString(SessionFile); // ***Performance file***
18347  // first reset the performance file name and open it before reloading it
18348  PerformanceFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
18349  // avoid characters in filename:= / \ : * ? " < > |
18350  PerformanceFileName = CurDir + "\\" + PERFLOG_DIR_NAME + "\\Log " + PerformanceFileName + "; " + RailwayTitle + "; " +
18351  TimetableTitle + ".txt";
18352  Utilities->PerformanceFile.open(PerformanceFileName.c_str(), std::ios_base::out);
18353  if(Utilities->PerformanceFile.fail())
18354  {
18355  ShowMessage("Performance logfile failed to open, logs won't be saved. Ensure that there is a folder named " + PERFLOG_DIR_NAME +
18356  " in the folder where the 'Railway.exe' program file resides");
18357  }
18358  // now reload the performance file
18359  LoadPerformanceFile(0, SessionFile);
18360  // addition at v2.4.0
18361  char TempChar;
18362  SessionFile.get(TempChar);
18363  while(!SessionFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '*'
18364  {
18365  SessionFile.get(TempChar);
18366  }
18367  if(SessionFile.eof()) // end of file
18368  {
18371  SessionFile.close(); // no TrainController->AvHoursIntValue & no failed trains
18372  // at v2.7.0 if find eof then don't need a value for ConsecSignalsRoute as that loaded same as PreferredRoute in interface
18373  }
18374  else //have v2.4.0 additions (train failures)
18375  {
18376  AnsiString DummyStr = Utilities->LoadFileString(SessionFile); // "**Additions after v2.3.1***" discarded (first '*' loaded earlier)
18377  TrainController->AvHoursIntValue = Utilities->LoadFileInt(SessionFile); // TrainController->AvHoursIntValue added at v2.4.0
18378  TrainController->NumFailures = Utilities->LoadFileInt(SessionFile); // number of train failures
18379  TrainController->MTBFHours = TrainController->AvHoursIntValue; // TTClockSpeed set to 1 in RestartSessionMode so no need to include here
18380  // now load any failed trains along with their OriginalPowerAtRail values
18381  DummyStr = Utilities->LoadFileString(SessionFile); // discard "***Failed Trains***"
18382  int ID = Utilities->LoadFileInt(SessionFile); // train ID or -1 for no more failed trains
18383  double PowerDouble;
18384  while(ID != -1)
18385  {
18386  PowerDouble = Utilities->LoadFileDouble(SessionFile); // ok TrainVector loaded at this stage (loaded in LoadSessionTrains)
18389  ID = Utilities->LoadFileInt(SessionFile);
18390  }
18391  // added at v2.7.0 - need value for ConsecSignalsRoute but might have eof here with older sessions so first test for that
18392  DummyStr = Utilities->LoadFileString(SessionFile); // "End of file at v2.4.0" discarded
18393  SessionFile.get(TempChar);
18394  while(!SessionFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '0' or '1'
18395  {
18396  SessionFile.get(TempChar);
18397  }
18398  if(!SessionFile.eof()) // not end of file - have v2.7.0 addition
18399  {
18400  if((TempChar != '0') && (TempChar != '1'))
18401  {
18402  throw Exception("TempChar value = " + AnsiString(TempChar) + ", should be 0 or 1");
18403  }
18404  ConsecSignalsRoute = true;
18405  if(TempChar == '0')
18406  {
18407  ConsecSignalsRoute = false;
18408  }
18409  }
18410 
18411  DummyStr = Utilities->LoadFileString(SessionFile); // "End of file at v2.7.0" discarded
18412  SessionFile.get(TempChar);
18413  while(!SessionFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '0' or '1'
18414  {
18415  SessionFile.get(TempChar);
18416  }
18417  if(!SessionFile.eof()) // not end of file - have at v2.9.1 additions
18418  {
18419  //TempChar now contains the first digit of EarlyExits as an ASCII character, so get the rest up to CRLF
18420  AnsiString TempString = TempChar;
18421  SessionFile.get(TempChar);
18422  while((TempChar != '\n') && (TempChar != '\0'))
18423  {
18424  TempString = TempString + TempChar;
18425  SessionFile.get(TempChar);
18426  }
18427  TrainController->EarlyExits = TempString.ToInt();
18430  TrainController->TotEarlyExitMins = float(Utilities->LoadFileDouble(SessionFile));
18431  TrainController->TotLateExitMins = float(Utilities->LoadFileDouble(SessionFile));
18432  }
18433 
18434  SessionFile.close();
18435  }
18436  // deal with other settings
18437  Display->DisplayOffsetH = TempDisplayOffsetH; // reset to saved values
18438  Display->DisplayOffsetV = TempDisplayOffsetV;
18439  Display->DisplayOffsetHHome = TempDisplayOffsetHHome;
18440  Display->DisplayOffsetVHome = TempDisplayOffsetVHome;
18441  // now set attributes to 1 for all LCs with barriers down
18442  for(unsigned int x = 0; x < Track->BarriersDownVector.size(); x++)
18443  {
18445  }
18446  Track->ChangingLCVector.clear();
18447  Track->CalcHLocMinEtc(10);
18449  SetLevel1Mode(27);
18450  if(Level2OperMode == PreStart)
18451  // this section added at v1.3.2 as otherwise only in MainScreenMouseDown2, and if load a session without clicking mouse on screen
18452  {
18453  // then delay unspecified though seems to be 0
18454  PointsFlashDuration = 0.0;
18457  }
18458  else
18459  {
18463  }
18464  RlyFile = true;
18465  SetCaption(3);
18467  }
18468  }
18469  else
18470  {
18471  ShowMessage("Session file integrity check failed, unable to load " + LoadSessionDialog->FileName);
18472  }
18473  Screen->Cursor = TCursor(-2); // Arrow;
18474  }
18475  Utilities->CallLogPop(1146);
18476  }
18477  catch(const Exception &e)
18478  {
18479  if((e.Message.Pos("esource") > 0) || (e.Message.Pos("arameter") > 0)) // 'Resource or Parameter, avoid capitals as may be OS dependent
18480  {
18481  Screen->Cursor = TCursor(-2); // Arrow;
18482  OutputLog1->Caption = "";
18483  OutputLog2->Caption = "";
18484  OutputLog3->Caption = "";
18485  OutputLog4->Caption = "";
18486  OutputLog5->Caption = "";
18487  OutputLog6->Caption = "";
18488  OutputLog7->Caption = "";
18489  OutputLog8->Caption = "";
18490  OutputLog9->Caption = "";
18491  OutputLog10->Caption = "";
18492  UnicodeString MessageStr =
18493  "Insufficient memory available to load the file, and partial load likely to be corrupt. Application will terminate. Try loading the session as the first action after reloading the program.";
18494 // UnicodeString MessageStr = "Last train loaded = " + UnicodeString(TrainController->LastTrainLoaded); //for debugging session train loading for many trains
18495  Application->MessageBox(MessageStr.c_str(), L"Out of memory", MB_OK | MB_ICONERROR);
18496  Application->Terminate();
18497  }
18498  else
18499  {
18500  ErrorLog(41, e.Message);
18501  }
18502  }
18503 }
18504 
18505 // ---------------------------------------------------------------------------
18506 
18507 void TInterface::SaveInterface(int Caller, std::ofstream &SessionFile)
18508 {
18509  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveInterface");
18510  if(Level2OperMode == PreStart)
18511  {
18512  Utilities->SaveFileString(SessionFile, AnsiString("PreStart"));
18513  }
18514  else
18515  {
18516  Utilities->SaveFileString(SessionFile, AnsiString("NotPreStart")); // covers both Paused & Operating
18517  }
18518  Utilities->SaveFileString(SessionFile, RailwayTitle);
18519  Utilities->SaveFileString(SessionFile, TimetableTitle);
18520  Utilities->SaveFileBool(SessionFile, PreferredRoute);
18521  Utilities->SaveFileBool(SessionFile, PreferredRoute);
18522 // changed at v2.7.0, was ConsecSignalsRoute here but if different to PreferredRoute (as can be from v2.7.0) then have
18523  Utilities->SaveFileBool(SessionFile, AutoSigsFlag);
18524 // error if try to load with an earlier prog version. ConsecSignalsRoute now moved to end of session file
18525  Utilities->SaveFileInt(SessionFile, Display->DisplayOffsetH);
18526  Utilities->SaveFileInt(SessionFile, Display->DisplayOffsetV);
18531  Utilities->SaveFileString(SessionFile, OutputLog1->Caption);
18532  Utilities->SaveFileString(SessionFile, OutputLog2->Caption);
18533  Utilities->SaveFileString(SessionFile, OutputLog3->Caption);
18534  Utilities->SaveFileString(SessionFile, OutputLog4->Caption);
18535  Utilities->SaveFileString(SessionFile, OutputLog5->Caption);
18536  Utilities->SaveFileString(SessionFile, OutputLog6->Caption);
18537  Utilities->SaveFileString(SessionFile, OutputLog7->Caption);
18538  Utilities->SaveFileString(SessionFile, OutputLog8->Caption);
18539  Utilities->SaveFileString(SessionFile, OutputLog9->Caption);
18540  Utilities->SaveFileString(SessionFile, OutputLog10->Caption);
18541 
18563  // ExcessLCDownMins saved after ***Interface*** at v2.2.0 (omitted in error earlier)
18564  Utilities->CallLogPop(1211);
18565 }
18566 
18567 // ---------------------------------------------------------------------------
18568 void TInterface::LoadInterface(int Caller, std::ifstream &SessionFile)
18569 {
18570  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadInterface");
18571  AnsiString OpMode = Utilities->LoadFileString(SessionFile);
18572 
18573  if(OpMode == "PreStart")
18574  {
18576  }
18577  else
18578  {
18580  }
18581  RailwayTitle = Utilities->LoadFileString(SessionFile);
18582  SavedFileName = CurDir + "\\" + RAILWAY_DIR_NAME + "\\" + RailwayTitle + ".rly";
18583 
18584  TimetableTitle = Utilities->LoadFileString(SessionFile);
18585  PreferredRoute = Utilities->LoadFileBool(SessionFile);
18586  ConsecSignalsRoute = Utilities->LoadFileBool(SessionFile);
18587  AutoSigsFlag = Utilities->LoadFileBool(SessionFile);
18588  Display->DisplayOffsetH = Utilities->LoadFileInt(SessionFile);
18589  Display->DisplayOffsetV = Utilities->LoadFileInt(SessionFile);
18594  OutputLog1->Caption = Utilities->LoadFileString(SessionFile);
18595  OutputLog2->Caption = Utilities->LoadFileString(SessionFile);
18596  OutputLog3->Caption = Utilities->LoadFileString(SessionFile);
18597  OutputLog4->Caption = Utilities->LoadFileString(SessionFile);
18598  OutputLog5->Caption = Utilities->LoadFileString(SessionFile);
18599  OutputLog6->Caption = Utilities->LoadFileString(SessionFile);
18600  OutputLog7->Caption = Utilities->LoadFileString(SessionFile);
18601  OutputLog8->Caption = Utilities->LoadFileString(SessionFile);
18602  OutputLog9->Caption = Utilities->LoadFileString(SessionFile);
18603  OutputLog10->Caption = Utilities->LoadFileString(SessionFile);
18604 
18612  TrainController->LateDeps = Utilities->LoadFileInt(SessionFile);
18626  session_api_->dump(); // update session INI file //added at v2.10.0
18627  Utilities->CallLogPop(1212);
18628 }
18629 
18630 // ---------------------------------------------------------------------------
18631 
18632 bool TInterface::CheckInterface(int Caller, std::ifstream &SessionFile)
18633 {
18634  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckInterface");
18635 
18636  AnsiString OpMode = "";
18637 
18638  if(!Utilities->CheckAndReadFileString(SessionFile, OpMode))
18639  {
18640  Utilities->CallLogPop(1767);
18641  return(false);
18642  }
18643  else if((OpMode != "PreStart") && (OpMode != "NotPreStart"))
18644  {
18645  Utilities->CallLogPop(1768);
18646  return(false);
18647  }
18648  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile)) // RailwayTitle
18649  {
18650  Utilities->CallLogPop(1213);
18651  return(false);
18652  }
18653  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile)) // TimetableTitle
18654  {
18655  Utilities->CallLogPop(1214);
18656  return(false);
18657  }
18658  if(!Utilities->CheckFileBool(SessionFile))
18659  {
18660  Utilities->CallLogPop(1216);
18661  return(false);
18662  }
18663  if(!Utilities->CheckFileBool(SessionFile))
18664  {
18665  Utilities->CallLogPop(1217);
18666  return(false);
18667  }
18668  if(!Utilities->CheckFileBool(SessionFile))
18669  {
18670  Utilities->CallLogPop(1218);
18671  return(false);
18672  }
18673  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
18674  {
18675  Utilities->CallLogPop(1409);
18676  return(false);
18677  }
18678  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
18679  {
18680  Utilities->CallLogPop(1486);
18681  return(false);
18682  }
18683  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
18684  {
18685  Utilities->CallLogPop(1487);
18686  return(false);
18687  }
18688  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
18689  {
18690  Utilities->CallLogPop(1488);
18691  return(false);
18692  }
18693  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
18694  {
18695  Utilities->CallLogPop(1489);
18696  return(false);
18697  }
18698  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
18699  {
18700  Utilities->CallLogPop(1528);
18701  return(false);
18702  }
18703  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
18704  {
18705  Utilities->CallLogPop(1725);
18706  return(false);
18707  }
18708  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
18709  {
18710  Utilities->CallLogPop(1726);
18711  return(false);
18712  }
18713  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
18714  {
18715  Utilities->CallLogPop(1727);
18716  return(false);
18717  }
18718  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
18719  {
18720  Utilities->CallLogPop(1728);
18721  return(false);
18722  }
18723  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
18724  {
18725  Utilities->CallLogPop(1730);
18726  return(false);
18727  }
18728  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
18729  {
18730  Utilities->CallLogPop(1731);
18731  return(false);
18732  }
18733  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
18734  {
18735  Utilities->CallLogPop(1732);
18736  return(false);
18737  }
18738  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
18739  {
18740  Utilities->CallLogPop(1733);
18741  return(false);
18742  }
18743  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
18744  {
18745  Utilities->CallLogPop(1734);
18746  return(false);
18747  }
18748  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
18749  {
18750  Utilities->CallLogPop(1789);
18751  return(false);
18752  }
18753  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18754  {
18755  Utilities->CallLogPop(1737);
18756  return(false);
18757  }
18758  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18759  {
18760  Utilities->CallLogPop(1738);
18761  return(false);
18762  }
18763  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18764  {
18765  Utilities->CallLogPop(1739);
18766  return(false);
18767  }
18768  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18769  {
18770  Utilities->CallLogPop(1740);
18771  return(false);
18772  }
18773  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18774  {
18775  Utilities->CallLogPop(1741);
18776  return(false);
18777  }
18778  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18779  {
18780  Utilities->CallLogPop(1742);
18781  return(false);
18782  }
18783  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18784  {
18785  Utilities->CallLogPop(1743);
18786  return(false);
18787  }
18788  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18789  {
18790  Utilities->CallLogPop(1744);
18791  return(false);
18792  }
18793  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18794  {
18795  Utilities->CallLogPop(1745);
18796  return(false);
18797  }
18798  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18799  {
18800  Utilities->CallLogPop(1746);
18801  return(false);
18802  }
18803  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18804  {
18805  Utilities->CallLogPop(1747);
18806  return(false);
18807  }
18808  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18809  {
18810  Utilities->CallLogPop(1748);
18811  return(false);
18812  }
18813  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18814  {
18815  Utilities->CallLogPop(1749);
18816  return(false);
18817  }
18818  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18819  {
18820  Utilities->CallLogPop(1750);
18821  return(false);
18822  }
18823  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18824  {
18825  Utilities->CallLogPop(1751);
18826  return(false);
18827  }
18828  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18829  {
18830  Utilities->CallLogPop(1752);
18831  return(false);
18832  }
18833  if(!Utilities->CheckFileDouble(SessionFile))
18834  {
18835  Utilities->CallLogPop(1753);
18836  return(false);
18837  }
18838  if(!Utilities->CheckFileDouble(SessionFile))
18839  {
18840  Utilities->CallLogPop(1754);
18841  return(false);
18842  }
18843  if(!Utilities->CheckFileDouble(SessionFile))
18844  {
18845  Utilities->CallLogPop(1755);
18846  return(false);
18847  }
18848  if(!Utilities->CheckFileDouble(SessionFile))
18849  {
18850  Utilities->CallLogPop(1756);
18851  return(false);
18852  }
18853  if(!Utilities->CheckFileDouble(SessionFile))
18854  {
18855  Utilities->CallLogPop(1757);
18856  return(false);
18857  }
18858  Utilities->CallLogPop(1219);
18859  return(true);
18860 }
18861 
18862 // ---------------------------------------------------------------------------
18863 
18864 bool TInterface::SaveTimetableToSessionFile(int Caller, std::ofstream &SessionFile, AnsiString SessionFileStr)
18865 {
18866  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTimetableToSessionFile," + SessionFileStr);
18867  if(!FileExists(TempTTFileName))
18868  {
18869  Utilities->CallLogPop(1862);
18870  return(false);
18871  }
18872  SessionFile.close(); // close & re-open in append & binary mode so LF characters copy as LFs & not CRLFs
18873  SessionFile.open(SessionFileStr.c_str(), std::ios_base::app | std::ios_base::binary); // file pointer set to end
18874 
18875  int Handle = FileOpen(TempTTFileName, fmOpenRead);
18876  int Count = 0;
18877 
18878  while(Handle < 0) // this type of file use failed when used in SaveTempTimetableFile when used to resave timetable.tmp from
18879  // temp .ttb file, but changed that to avoid so many rapid file actions in quick succession & been OK since
18880  // then, but nevertheless have 10 retries before giving message to be on safe side
18881  {
18882  Handle = FileOpen(TempTTFileName, fmOpenRead);
18883  Count++;
18884  Delay(1, 50); // 50mSec delay between tries
18885  if(Count > 10)
18886  {
18887  ShowMessage("Failed to open temporary timetable file. Unable to save the session");
18888  Utilities->CallLogPop(1221);
18889  return(false);
18890  }
18891  }
18892 
18893  char *Buffer = new char[10000];
18894  int BytesRead;
18895 
18896  while(true)
18897  {
18898  BytesRead = FileRead(Handle, Buffer, 10000);
18899  SessionFile.write(Buffer, BytesRead);
18900  if(BytesRead < 10000)
18901  {
18902  break;
18903  }
18904  }
18905  delete[] Buffer;
18906  FileClose(Handle);
18907 
18908  SessionFile.close(); // close & re-open in append & text out mode as before so can write text
18909  SessionFile.open(SessionFileStr.c_str(), std::ios_base::app | std::ios_base::out); // file pointer set to end
18910 
18911  Utilities->SaveFileString(SessionFile, "***End***"); // marker for end of timetable
18912 // now need to save the TrainOperatingData so can be loaded back into the timetable as is
18913  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.size());
18914  for(unsigned int x = 0; x < TrainController->TrainDataVector.size(); x++)
18915  {
18916  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size());
18917  for(unsigned int y = 0; y < TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size(); y++)
18918  {
18919  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).TrainID);
18920  Utilities->SaveFileInt(SessionFile, (short)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).EventReported));
18921  Utilities->SaveFileInt(SessionFile, (short)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).RunningEntry));
18922  }
18923  }
18924  Utilities->CallLogPop(1220);
18925  return(true);
18926 }
18927 
18928 // ---------------------------------------------------------------------------
18929 
18930 bool TInterface::SaveTimetableToErrorFile(int Caller, std::ofstream &ErrorFile, AnsiString ErrorFileStr, AnsiString TimetableFileName)
18931 {
18932  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTimetableToErrorFile," + ErrorFileStr + "," + TimetableFileName);
18933  if(!FileExists(TimetableFileName))
18934  {
18935  Utilities->CallLogPop(1863);
18936  return(false);
18937  }
18938  ErrorFile.close(); // close & re-open in append & binary mode so LF characters copy as LFs & not CRLFs
18939  ErrorFile.open(ErrorFileStr.c_str(), std::ios_base::app | std::ios_base::binary); // file pointer set to end
18940 
18941  int Handle = FileOpen(TimetableFileName, fmOpenRead);
18942  int Count = 0;
18943 
18944  while(Handle < 0) // this type of file use failed when used in SaveTempTimetableFile when used to resave timetable.tmp from
18945  // temp .ttb file, but changed that to avoid so many rapid file actions in quick succession & been OK since
18946  // then, but nevertheless have 10 retries before giving message to be on safe side
18947  {
18948  Handle = FileOpen(TimetableFileName, fmOpenRead);
18949  Count++;
18950  Delay(5, 50); // 50mSec delay between tries
18951  if(Count > 10)
18952  {
18953  Utilities->CallLogPop(1835);
18954  return(false);
18955  }
18956  }
18957 
18958  char *Buffer = new char[10000];
18959  int BytesRead;
18960 
18961  while(true)
18962  {
18963  BytesRead = FileRead(Handle, Buffer, 10000);
18964  ErrorFile.write(Buffer, BytesRead);
18965  if(BytesRead < 10000)
18966  {
18967  break;
18968  }
18969  }
18970  delete[] Buffer;
18971  FileClose(Handle);
18972 
18973  ErrorFile.close(); // close & re-open in append & text out mode as before so can write text
18974  ErrorFile.open(ErrorFileStr.c_str(), std::ios_base::app | std::ios_base::out); // file pointer set to end
18975 
18976  Utilities->SaveFileString(ErrorFile, "***End of timetable***"); // marker for end of timetable
18977  Utilities->CallLogPop(1836);
18978  return(true);
18979 }
18980 
18981 // ---------------------------------------------------------------------------
18982 
18983 bool TInterface::LoadTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
18984 // the .ttb section is delimited by "***End***"
18985 // create the temporary timetable file in the working folder exactly like the original
18986 {
18987  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTimetableFromSessionFile");
18988  // reset all message flags, stops them being given twice (shouldn't be needed here but add for safety) //new at v2.4.0
18989  TrainController->SSHigh = false;
18990  TrainController->MRSHigh = false;
18991  TrainController->MRSLow = false;
18992  TrainController->MassHigh = false;
18993  TrainController->BFHigh = false;
18994  TrainController->BFLow = false;
18995  TrainController->PwrHigh = false;
18996  TrainController->SigSHigh = false;
18997  TrainController->SigSLow = false;
18998  if((TempTTFileName != "") && FileExists(TempTTFileName))
18999  {
19000  DeleteFile(TempTTFileName);
19001  }
19002  int TempTTFileNumber = 0;
19003 
19004  while(FileExists(CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp"))
19005  {
19006  TempTTFileNumber++;
19007  }
19008  TempTTFileName = CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp";
19009 
19010  std::ofstream TTBFile(TempTTFileName.c_str()); // use text mode as SessionFile is in text mode, so CRLFs read as LFs, and LFs write as CRLFs.
19011  int Count;
19012  char Zero = '\0';
19013 
19014  if(!TTBFile.fail())
19015  {
19016  char *Buffer = new char[10000]; // can't use LoadFileString as that expects a '\0' delimiter
19017  char TempChar = (char)(SessionFile.peek()); // have a look at the next character, if it's '\n'
19018  if(TempChar == '\n')
19019  {
19020  SessionFile.get(TempChar); // then get rid of it, else leave it in as part of the first line
19021  }
19022  if(!SessionFile.getline(Buffer, 10000, '\0'))
19023  {
19024  TTBFile.close();
19025  DeleteFile(TempTTFileName);
19026  delete[] Buffer;
19027  Utilities->CallLogPop(1222);
19028  return(false);
19029  }
19030  Count = 0;
19031  for(int x = 0; x < 10000; x++)
19032  {
19033  if(Buffer[x] != '\0')
19034  {
19035  Count++;
19036  }
19037  else
19038  {
19039  break;
19040  }
19041  }
19042  while(AnsiString(Buffer) != "***End***")
19043  {
19044  TTBFile.write(Buffer, Count);
19045  TTBFile.write(&Zero, 1);
19046 // TTBFile.write(&NewLine, 1);
19047  if(!SessionFile.getline(Buffer, 10000, '\0'))
19048  {
19049  TTBFile.close();
19050  DeleteFile(TempTTFileName);
19051  delete[] Buffer;
19052  Utilities->CallLogPop(1223);
19053  return(false);
19054  }
19055  Count = 0;
19056  for(int x = 0; x < 10000; x++)
19057  {
19058  if(Buffer[x] != '\0')
19059  {
19060  Count++;
19061  }
19062  else
19063  {
19064  break;
19065  }
19066  }
19067  }
19068  TTBFile.close();
19069  delete[] Buffer;
19070 // SaveTempTimetableFile(1, TTBFileName); no need, already has required name
19071 // now create the internal timetable from the .tmp file
19072  bool GiveMessagesFalse = false;
19073  bool CheckLocationsExistInRailwayTrue = true;
19074  if(TrainController->TimetableIntegrityCheck(1, TempTTFileName.c_str(), GiveMessagesFalse, CheckLocationsExistInRailwayTrue))
19075  {
19076  std::ifstream TTBLFile(TempTTFileName.c_str(), std::ios_base::binary);
19077  if(TTBLFile.is_open())
19078  {
19079  bool SessionFileTrue = true;
19080  if(!(BuildTrainDataVectorForLoadFile(1, TTBLFile, GiveMessagesFalse, CheckLocationsExistInRailwayTrue, SessionFileTrue)))
19081  {
19082  TTBLFile.close();
19083  DeleteFile(TempTTFileName);
19084  Utilities->CallLogPop(1224);
19085  return(false);
19086  }
19087  }
19088  else
19089  {
19090  DeleteFile(TempTTFileName);
19091  Utilities->CallLogPop(1225);
19092  return(false);
19093  }
19094  } // if(FileIntegrityCheck(TTBFileName.c_str()))
19095  else
19096  {
19097  DeleteFile(TempTTFileName);
19098  Utilities->CallLogPop(1226);
19099  return(false);
19100  }
19101 // DeleteFile(TempTTFileName); no, need to save it for later session saves
19102 
19103  // now need to load the TrainOperatingData so can be loaded back into the timetable
19104  int NumberOfTrainEntries = Utilities->LoadFileInt(SessionFile);
19105  if(NumberOfTrainEntries != (int)(TrainController->TrainDataVector.size()))
19106  {
19107  Utilities->CallLogPop(1811);
19108  return(false);
19109  }
19110  for(int x = 0; x < NumberOfTrainEntries; x++)
19111  {
19112  int NumberOfTrains = Utilities->LoadFileInt(SessionFile);
19113  if(NumberOfTrains != (int)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size()))
19114  {
19115  Utilities->CallLogPop(1812);
19116  return(false);
19117  }
19118  for(int y = 0; y < NumberOfTrains; y++)
19119  {
19120  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).TrainID = Utilities->LoadFileInt(SessionFile);
19121  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).EventReported = (TActionEventType)(Utilities->LoadFileInt(SessionFile));
19122  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).RunningEntry = (TRunningEntry)(Utilities->LoadFileInt(SessionFile));
19123  }
19124  }
19125  Utilities->CallLogPop(1227);
19126  return(true);
19127  }
19128  else
19129  {
19130  Utilities->CallLogPop(1228);
19131  return(false);
19132  }
19133 }
19134 
19135 // ---------------------------------------------------------------------------
19136 
19137 bool TInterface::CheckTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
19138 // the .ttb section is delimited by '\0' followed by "***End***" & has been saved in binary mode, i.e. no '\0'
19139 // string delimiters between entries, this check function just checks the (non-zero terminated) string entries in the file without
19140 // trying to build a timetable - that's done during load
19141 {
19142  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTimetableFromSessionFile");
19143  AnsiString OutString;
19144 
19145  if(!Utilities->CheckAndReadFileString(SessionFile, OutString))
19146  {
19147  Utilities->CallLogPop(1229);
19148  return(false);
19149  }
19150  while(OutString != "***End***")
19151  {
19152  if(!Utilities->CheckAndReadFileString(SessionFile, OutString))
19153  {
19154  Utilities->CallLogPop(1230);
19155  return(false);
19156  }
19157  }
19158 // now need to check the TrainOperatingData, which was saved in text mode
19159  if(SessionFile.fail())
19160  {
19161  Utilities->CallLogPop(1231);
19162  return(false);
19163  }
19164  int NumberOfTrainEntries;
19165 
19166  if(!Utilities->CheckAndReadFileInt(SessionFile, 0, 10000, NumberOfTrainEntries))
19167  {
19168  Utilities->CallLogPop(1232);
19169  return(false);
19170  }
19171  for(int x = 0; x < NumberOfTrainEntries; x++)
19172  {
19173  int NumberOfTrains;
19174  if(!Utilities->CheckAndReadFileInt(SessionFile, 0, 10000, NumberOfTrains))
19175  {
19176  Utilities->CallLogPop(1233);
19177  return(false);
19178  }
19179  for(int y = 0; y < NumberOfTrains; y++)
19180  {
19181  if(!Utilities->CheckFileInt(SessionFile, -1, 1000000)) // TrainID
19182  {
19183  Utilities->CallLogPop(1234);
19184  return(false);
19185  }
19186  if(!Utilities->CheckFileInt(SessionFile, 0, 30)) // EventReported
19187  {
19188  Utilities->CallLogPop(1235);
19189  return(false);
19190  }
19191  if(!Utilities->CheckFileInt(SessionFile, 0, 2)) // RunningEntry
19192  {
19193  Utilities->CallLogPop(1236);
19194  return(false);
19195  }
19196  }
19197  }
19198  Utilities->CallLogPop(1237);
19199  return(true);
19200 }
19201 
19202 // ---------------------------------------------------------------------------
19203 
19204 bool TInterface::BuildTrainDataVectorForLoadFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway, bool SessionFile)
19205 {
19206  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildTrainDataVectorForLoadFile," + AnsiString((short)GiveMessages));
19207  TrainController->TrainDataVector.clear(); // get rid of any earlier timetable
19208  bool EndOfFile = false;
19209  int Count = 0;
19210  char *TrainTimetableString = new char[10000]; // enough for ~ 200 stations at 50 chars/station, should be adequate!
19211 
19212  while(!EndOfFile)
19213  {
19214  TTBLFile.getline(TrainTimetableString, 10000, '\0');
19215  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
19216  {
19217  // may still have eof even if read a line (no CRLF at end), and
19218  // if so need to process it
19219  EndOfFile = true;
19220  break;
19221  }
19222  AnsiString OneLine(TrainTimetableString);
19223  bool FinalCallTrue = true;
19224  while((Count == 0) && !TrainController->ProcessOneTimetableLine(3, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages,
19225  CheckLocationsExistInRailway)) // get rid of lines before the start time
19226  {
19227  TTBLFile.getline(TrainTimetableString, 10000, '\0');
19228  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
19229  {
19230  TTBLFile.close();
19231  throw Exception("Timetable FinalCall error - no start time on own line, Count = 0");
19232  }
19233  OneLine = AnsiString(TrainTimetableString);
19234  }
19235  // here when have accepted the start time
19236  if(Count == 0)
19237  {
19238  Count++; // increment past the start time
19239  TTBLFile.getline(TrainTimetableString, 10000, '\0'); // get next line after start time
19240  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
19241  {
19242  EndOfFile = true;
19243  OneLine = "";
19244  }
19245  else
19246  {
19247  OneLine = AnsiString(TrainTimetableString);
19248  }
19249  }
19250  if(!TrainController->ProcessOneTimetableLine(4, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages, CheckLocationsExistInRailway))
19251  {
19252  TTBLFile.close();
19253  throw Exception("Timetable FinalCall error in processing one timetable line, Count = " + AnsiString(Count));
19254  }
19255  if(EndOfFile && (Count < 2)) // Timetable must contain at least two relevant lines, one for start time and at least one train
19256  {
19257  TTBLFile.close();
19258  throw Exception("Timetable FinalCall error - too few or no relevant entries, Count = " + AnsiString(Count));
19259  }
19260  Count++;
19261  }
19262  TTBLFile.close();
19263  delete[] TrainTimetableString;
19264  bool TwoLocationFlag; //not used in LoadFile
19265 // here when first pass actions completed successfully
19266  if(!TrainController->SecondPassActions(0, GiveMessages, TwoLocationFlag)) // Check for matching join/split HeadCodes, check increasing times & matching split/join
19267  // times, complete arrival & departure times for each TT line, check & complete train info for each type of start,
19268  // messages given in function if errors & vector cleared
19269  {
19270  if(GiveMessages)
19271  {
19272  ShowMessage("Timetable secondary integrity check failed - unable to load");
19273  }
19274  Utilities->CallLogPop(1238);
19275  return(false);
19276  }
19277  else
19278  {
19279 // TimetableLoaded = true;
19280  if(!SessionFile) // new timetable being loaded so need new TimetableTitle, if SessionFile true then already have it from LoadInterface
19281  {
19282  for(int x = TimetableDialog->FileName.Length(); x > 0; x--)
19283  {
19284  if(TimetableDialog->FileName[x] == '\\')
19285  {
19286  TimetableTitle = TimetableDialog->FileName.SubString(x + 1, TimetableDialog->FileName.Length() - x - 4);
19287  SetCaption(4);
19288  break;
19289  }
19290  }
19291  }
19292 // if(GiveMessages) //only set BaseMode if have manually loaded a timetable changed for the below in v2.4.0
19293  if(!SessionFile) // only set BaseMode if have manually loaded a timetable, i.e SessionFile is false
19294  {
19295  Level1Mode = BaseMode;
19296  SetLevel1Mode(28);
19297  }
19298  }
19299  Utilities->CallLogPop(1239);
19300  return(true);
19301 }
19302 
19303 // ---------------------------------------------------------------------------
19304 
19305 bool TInterface::BuildTrainDataVectorForValidateFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway)
19306 {
19307  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildTrainDataVectorForValidateFile," + AnsiString((short)GiveMessages));
19308  TrainController->TrainDataVector.clear(); // get rid of any earlier timetable
19309  bool EndOfFile = false;
19310  int Count = 0;
19311  char *TrainTimetableString = new char[10000]; // enough for ~ 200 stations at 50 chars/station, should be adequate!
19312 
19313  while(!EndOfFile)
19314  {
19315  TTBLFile.getline(TrainTimetableString, 10000, '\0');
19316  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
19317  {
19318  // may still have eof even if read a line (no CRLF at end), and
19319  // if so need to process it
19320  EndOfFile = true;
19321  break;
19322  }
19323  AnsiString OneLine(TrainTimetableString);
19324  bool FinalCallTrue = true;
19325  while((Count == 0) && !TrainController->ProcessOneTimetableLine(0, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages,
19326  CheckLocationsExistInRailway)) // get rid of lines before the start time
19327  {
19328  TTBLFile.getline(TrainTimetableString, 10000, '\0');
19329  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
19330  {
19331  TTBLFile.close();
19332  throw Exception("Timetable FinalCall error - no start time on own line, Count = 0");
19333  }
19334  OneLine = AnsiString(TrainTimetableString);
19335  }
19336  // here when have accepted the start time
19337  if(Count == 0)
19338  {
19339  Count++; // increment past the start time
19340  TTBLFile.getline(TrainTimetableString, 10000, '\0'); // get next line after start time
19341  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
19342  {
19343  EndOfFile = true;
19344  OneLine = "";
19345  }
19346  else
19347  {
19348  OneLine = AnsiString(TrainTimetableString);
19349  }
19350  }
19351  if(!TrainController->ProcessOneTimetableLine(1, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages, CheckLocationsExistInRailway))
19352  {
19353  TTBLFile.close();
19354  throw Exception("Timetable FinalCall error in processing one timetable line, Count = " + AnsiString(Count));
19355  }
19356  if(EndOfFile && (Count < 2)) // Timetable must contain at least two relevant lines, one for start time and at least one train
19357  {
19358  TTBLFile.close();
19359  throw Exception("Timetable FinalCall error - too few or no relevant entries, Count = " + AnsiString(Count));
19360  }
19361  Count++;
19362  }
19363  TTBLFile.close();
19364  delete[] TrainTimetableString;
19365  bool TwoLocationFlag;
19366 // here when first pass actions completed successfully
19367  if(!TrainController->SecondPassActions(1, GiveMessages, TwoLocationFlag)) // Check for matching join/split HeadCodes, check increasing times & matching split/join
19368  // times, complete arrival & departure times for each TT line, check & complete train info for each type of start,
19369  // messages given in function if errors & vector cleared
19370  {
19371 // if(GiveMessages) ShowMessage("Timetable secondary integrity check failed");
19372 // above dropped in v2.4.0 as all called functions give own messages
19373  Utilities->CallLogPop(1665);
19374  return(false);
19375  }
19376  else if(TwoLocationFlag) //i.e returns true but have services with two or more locations without a cdt between //added at v2.9.1
19377  {
19378  AnsiString AllServices = "", Suffix = "";
19379  int Count = 1;
19381  {
19382  TwoLocationNamePanel->Top = TimetableEditPanel->Top + ((TimetableEditPanel->Height - TwoLocationNamePanel->Height) / 2);
19383  TwoLocationNamePanel->Left = TimetableEditPanel->Left + ((TimetableEditPanel->Width - TwoLocationNamePanel->Width) / 2);
19384  for(TTrainController::TServiceCallingLocsList::iterator TLLIt = TrainController->TwoLocationList.begin(); TLLIt != TrainController->TwoLocationList.end(); TLLIt++)
19385  {
19386  if(Count <= 5)
19387  {
19388  AllServices = AllServices + *TLLIt + ", ";
19389  }
19390  Count++;
19391  }
19392  if(Count > 6) //if exactly 5 entered then Count will be 6, Count always 1 more than entered
19393  {
19394  Suffix = "(more than 5, first 5 are) ";
19395  }
19396  if(Count > 2) //more than 1
19397  {
19398  TwoLocationNameLabel->Caption = "The following services have two or more locations with the same name without a change of\n"
19399  "direction between them. If this isn't intended then please correct them.\n\n"
19400  "Before ticking the check box please be sure that all services are correct.\n\n"
19401  "Services: " + Suffix + " " + AllServices;
19402  }
19403  else
19404  {
19405  TwoLocationNameLabel->Caption = "The following service has two or more locations with the same name without a change of\n"
19406  "direction between them. If this isn't intended then please correct it.\n\n"
19407  "Service: " + AllServices;
19408  }
19409  TwoLocationNamePanel->Visible = true;
19410  TwoLocationNamePanel->BringToFront();
19411  ShowHideTTButton->Enabled = false;
19412  ExitTTModeButton->Enabled = false;
19413  TimetableEditPanel->Enabled = false;
19414  }
19415  }
19416  Utilities->CallLogPop(1666);
19417  return(true);
19418 }
19419 
19420 // ---------------------------------------------------------------------------
19421 
19422 bool TInterface::SessionFileIntegrityCheck(int Caller, AnsiString FileName)
19423 /* Here need to check as far as timetable, then go back and load the track, because the timetable compilation check
19424 relies on the track vector and map being in place. Won't affect the later load because the vector and map are cleared
19425 before loading.
19426 
19427 Although this appears cumbersome, I initially used tellg() & seekg() to reposition the file pointer without having to do
19428 all this backtracking. However after many problems I eventually found that tellg() sometimes returns false values,
19429 which cause problems when reloaded using seekg(). This must be a compiler problem, though I could find no mention of it
19430 in the CBuilder4 issues list or on the web. The full write-up is at the end of this unit.
19431 
19432 Also, with hindsight, I wish I had just saved and reloaded the timetable vectors rather than the text of the timetable. That
19433 would probably have been easier. To change it now though would cause compatibility problems with sessions created by earlier versions.
19434 */
19435 {
19436  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SessionFileIntegrityCheck," + FileName);
19437  std::ifstream InFile(FileName.c_str());
19438 // first pass as far as timetable
19439  int NumberOfActiveElements;
19440  bool GraphicsFollow = false;
19441 
19442  if(InFile.is_open())
19443  {
19445  // expected to be "***Interface***" for original version or "Version + : ***Interface***" for later releases + ExcessLCDownMins added as float at v2.3.0
19446  {
19447  InFile.close();
19448  Utilities->CallLogPop(1240);
19449  return(false);
19450  }
19451  if(!CheckInterface(0, InFile))
19452  {
19453  InFile.close();
19454  Utilities->CallLogPop(1241);
19455  return(false);
19456  }
19457  // check track elements
19458  if(!Utilities->CheckAndCompareFileString(InFile, "***Track***"))
19459  {
19460  InFile.close();
19461  Utilities->CallLogPop(1242);
19462  return(false);
19463  }
19464  if(!Track->CheckTrackElementsInFile(2, NumberOfActiveElements, GraphicsFollow, InFile))
19465  {
19466  InFile.close();
19467  Utilities->CallLogPop(1243);
19468  return(false);
19469  }
19470  if(InFile.fail())
19471  {
19472  InFile.close();
19473  Utilities->CallLogPop(1244);
19474  return(false);
19475  }
19476  // check text elements
19477  if(!Utilities->CheckAndCompareFileString(InFile, "***Text***"))
19478  {
19479  InFile.close();
19480  Utilities->CallLogPop(1245);
19481  return(false);
19482  }
19483  if(!TextHandler->CheckTextElementsInFile(1, InFile))
19484  {
19485  InFile.close();
19486  Utilities->CallLogPop(1246);
19487  return(false);
19488  }
19489  if(InFile.fail())
19490  {
19491  InFile.close();
19492  Utilities->CallLogPop(1247);
19493  return(false);
19494  }
19495  // check PrefDir elements
19496  if(!Utilities->CheckAndCompareFileString(InFile, "***PrefDirs***"))
19497  {
19498  InFile.close();
19499  Utilities->CallLogPop(1248);
19500  return(false);
19501  }
19502  if(!EveryPrefDir->CheckOnePrefDir(1, NumberOfActiveElements, InFile))
19503  {
19504  InFile.close();
19505  Utilities->CallLogPop(1249);
19506  return(false);
19507  }
19508  if(InFile.fail())
19509  {
19510  InFile.close();
19511  Utilities->CallLogPop(1250);
19512  return(false);
19513  }
19514  // check graphics
19515  if(GraphicsFollow)
19516  {
19517  if(!Track->CheckUserGraphics(1, InFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
19518  {
19519  InFile.close();
19520  Utilities->CallLogPop(2187);
19521  return(false);
19522  }
19523  if(InFile.fail())
19524  {
19525  InFile.close();
19526  Utilities->CallLogPop(2188);
19527  return(false);
19528  }
19529  }
19530  // check routes
19531  if(!Utilities->CheckAndCompareFileString(InFile, "***Routes***"))
19532  {
19533  InFile.close();
19534  Utilities->CallLogPop(1251);
19535  return(false);
19536  }
19537  if(!AllRoutes->CheckRoutes(0, NumberOfActiveElements, InFile))
19538  {
19539  InFile.close();
19540  Utilities->CallLogPop(1252);
19541  return(false);
19542  }
19543  if(InFile.fail())
19544  {
19545  InFile.close();
19546  Utilities->CallLogPop(1253);
19547  return(false);
19548  }
19549  // check LockedRoutes
19550  if(!Utilities->CheckAndCompareFileString(InFile, "***Locked routes***"))
19551  {
19552  InFile.close();
19553  Utilities->CallLogPop(1254);
19554  return(false);
19555  }
19556  if(!TrainController->CheckSessionLockedRoutes(0, InFile))
19557  {
19558  InFile.close();
19559  Utilities->CallLogPop(1255);
19560  return(false);
19561  }
19562  if(InFile.fail())
19563  {
19564  InFile.close();
19565  Utilities->CallLogPop(1256);
19566  return(false);
19567  }
19568  // check ContinuationAutoSigs
19569  if(!Utilities->CheckAndCompareFileString(InFile, "***ContinuationAutoSigEntries***"))
19570  {
19571  InFile.close();
19572  Utilities->CallLogPop(1257);
19573  return(false);
19574  }
19576  {
19577  InFile.close();
19578  Utilities->CallLogPop(1258);
19579  return(false);
19580  }
19581  if(InFile.fail())
19582  {
19583  InFile.close();
19584  Utilities->CallLogPop(1259);
19585  return(false);
19586  }
19587  // check BarriersDownVector, but ensure backwards compatibility with earlier files which don't have this section
19588  AnsiString TempString = Utilities->LoadFileString(InFile);
19589  if((TempString != "***BarriersDownVector***") && (TempString != "***Timetable***"))
19590  {
19591  InFile.close();
19592  Utilities->CallLogPop(1964);
19593  return(false);
19594  }
19595  if(TempString == "***BarriersDownVector***")
19596  {
19597  if(!Track->CheckActiveLCVector(0, InFile))
19598  {
19599  InFile.close();
19600  Utilities->CallLogPop(1965);
19601  return(false);
19602  }
19603  if(InFile.fail())
19604  {
19605  InFile.close();
19606  Utilities->CallLogPop(1966);
19607  return(false);
19608  }
19609  if(!Utilities->CheckAndCompareFileString(InFile, "***Timetable***"))
19610  {
19611  InFile.close();
19612  Utilities->CallLogPop(1260);
19613  return(false);
19614  }
19615  }
19616  // check timetable (marker string already checked immediately above)
19617  if(!CheckTimetableFromSessionFile(0, InFile))
19618  {
19619  InFile.close();
19620  Utilities->CallLogPop(1261);
19621  return(false);
19622  }
19623  if(InFile.fail())
19624  {
19625  InFile.close();
19626  Utilities->CallLogPop(1262);
19627  return(false);
19628  }
19629  }
19630  else
19631  {
19632  InFile.close();
19633 // ShowMessage("Session file failed to open, reason not known, unable to load session."); message given in calling function if returns false
19634  Utilities->CallLogPop(1263);
19635  return(false);
19636  }
19637 // now ready for the 2nd pass for timetable loading and checking
19638  InFile.close();
19639  InFile.open(FileName.c_str());
19640  if(InFile.is_open())
19641  {
19643  {
19644  InFile.close();
19645  Utilities->CallLogPop(1264);
19646  return(false);
19647  }
19648  if(!CheckInterface(1, InFile))
19649  {
19650  InFile.close();
19651  Utilities->CallLogPop(1265);
19652  return(false);
19653  }
19654  // load track elements
19655  if(!Utilities->CheckAndCompareFileString(InFile, "***Track***"))
19656  {
19657  InFile.close();
19658  Utilities->CallLogPop(1266);
19659  return(false);
19660  }
19661  bool GraphicsFollow = false;
19662  Track->LoadTrack(2, InFile, GraphicsFollow); // load the track this time
19663  if(InFile.fail())
19664  {
19665  InFile.close();
19666  Utilities->CallLogPop(1267);
19667  return(false);
19668  }
19669  // check text elements
19670  if(!Utilities->CheckAndCompareFileString(InFile, "***Text***"))
19671  {
19672  InFile.close();
19673  Utilities->CallLogPop(1268);
19674  return(false);
19675  }
19676  if(!TextHandler->CheckTextElementsInFile(2, InFile))
19677  {
19678  InFile.close();
19679  Utilities->CallLogPop(1269);
19680  return(false);
19681  }
19682  if(InFile.fail())
19683  {
19684  InFile.close();
19685  Utilities->CallLogPop(1270);
19686  return(false);
19687  }
19688  // check PrefDir elements
19689  if(!Utilities->CheckAndCompareFileString(InFile, "***PrefDirs***"))
19690  {
19691  InFile.close();
19692  Utilities->CallLogPop(1271);
19693  return(false);
19694  }
19695  if(!EveryPrefDir->CheckOnePrefDir(2, NumberOfActiveElements, InFile))
19696  {
19697  InFile.close();
19698  Utilities->CallLogPop(1272);
19699  return(false);
19700  }
19701  if(InFile.fail())
19702  {
19703  InFile.close();
19704  Utilities->CallLogPop(1273);
19705  return(false);
19706  }
19707  // check graphics
19708  if(GraphicsFollow)
19709  {
19710  if(!Track->CheckUserGraphics(2, InFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
19711  {
19712  InFile.close();
19713  Utilities->CallLogPop(2189);
19714  return(false);
19715  }
19716  if(InFile.fail())
19717  {
19718  InFile.close();
19719  Utilities->CallLogPop(2190);
19720  return(false);
19721  }
19722  }
19723  // check routes
19724  if(!Utilities->CheckAndCompareFileString(InFile, "***Routes***"))
19725  {
19726  InFile.close();
19727  Utilities->CallLogPop(1274);
19728  return(false);
19729  }
19730  if(!AllRoutes->CheckRoutes(1, NumberOfActiveElements, InFile))
19731  {
19732  InFile.close();
19733  Utilities->CallLogPop(1275);
19734  return(false);
19735  }
19736  if(InFile.fail())
19737  {
19738  InFile.close();
19739  Utilities->CallLogPop(1276);
19740  return(false);
19741  }
19742  // check LockedRoutes
19743  if(!Utilities->CheckAndCompareFileString(InFile, "***Locked routes***"))
19744  {
19745  InFile.close();
19746  Utilities->CallLogPop(1277);
19747  return(false);
19748  }
19749  if(!TrainController->CheckSessionLockedRoutes(1, InFile))
19750  {
19751  InFile.close();
19752  Utilities->CallLogPop(1278);
19753  return(false);
19754  }
19755  if(InFile.fail())
19756  {
19757  InFile.close();
19758  Utilities->CallLogPop(1279);
19759  return(false);
19760  }
19761  // check ContinuationAutoSigs
19762  if(!Utilities->CheckAndCompareFileString(InFile, "***ContinuationAutoSigEntries***"))
19763  {
19764  InFile.close();
19765  Utilities->CallLogPop(1280);
19766  return(false);
19767  }
19769  {
19770  InFile.close();
19771  Utilities->CallLogPop(1281);
19772  return(false);
19773  }
19774  if(InFile.fail())
19775  {
19776  InFile.close();
19777  Utilities->CallLogPop(1282);
19778  return(false);
19779  }
19780  // check BarriersDownVector, but ensure backwards compatibility with earlier files which don't have this section
19781  AnsiString TempString = Utilities->LoadFileString(InFile);
19782  if((TempString != "***BarriersDownVector***") && (TempString != "***Timetable***"))
19783  {
19784  InFile.close();
19785  Utilities->CallLogPop(1967);
19786  return(false);
19787  }
19788  if(TempString == "***BarriersDownVector***")
19789  {
19790  if(!Track->CheckActiveLCVector(0, InFile))
19791  {
19792  InFile.close();
19793  Utilities->CallLogPop(1968);
19794  return(false);
19795  }
19796  if(InFile.fail())
19797  {
19798  InFile.close();
19799  Utilities->CallLogPop(1969);
19800  return(false);
19801  }
19802  if(!Utilities->CheckAndCompareFileString(InFile, "***Timetable***"))
19803  {
19804  InFile.close();
19805  Utilities->CallLogPop(1283);
19806  return(false);
19807  }
19808  }
19809  // check timetable (marker string already checked)
19810  if(!LoadTimetableFromSessionFile(1, InFile))
19811  {
19812  InFile.close();
19813  Utilities->CallLogPop(1284);
19814  return(false);
19815  }
19816  if(InFile.fail())
19817  {
19818  InFile.close();
19819  Utilities->CallLogPop(1285);
19820  return(false);
19821  }
19822  // check timetable clock
19823  if(!Utilities->CheckAndCompareFileString(InFile, "***TimetableClock***"))
19824  {
19825  InFile.close();
19826  Utilities->CallLogPop(1286);
19827  return(false);
19828  }
19829  if(!Utilities->CheckFileDouble(InFile))
19830  {
19831  InFile.close();
19832  Utilities->CallLogPop(1287);
19833  return(false);
19834  }
19835  // check trains
19836  if(!Utilities->CheckAndCompareFileString(InFile, "***Trains***"))
19837  {
19838  InFile.close();
19839  Utilities->CallLogPop(1288);
19840  return(false);
19841  }
19842  if(!TrainController->CheckSessionTrains(0, InFile))
19843  {
19844  InFile.close();
19845  Utilities->CallLogPop(1289);
19846  return(false);
19847  }
19848  if(InFile.fail())
19849  {
19850  InFile.close();
19851  Utilities->CallLogPop(1290);
19852  return(false);
19853  }
19854  if(!Utilities->CheckAndCompareFileString(InFile, "***Performance file***"))
19855  {
19856  InFile.close();
19857  Utilities->CallLogPop(1291);
19858  return(false);
19859  }
19860  if(!CheckPerformanceFile(0, InFile))
19861  {
19862  InFile.close();
19863  Utilities->CallLogPop(1292);
19864  return(false);
19865  }
19866  char TempChar;
19867  InFile.get(TempChar);
19868  while(!InFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '*'
19869  {
19870  InFile.get(TempChar);
19871  }
19872  if(!InFile.eof()) // additional checks needed
19873  {
19874  if(!Utilities->CheckFileString(InFile))
19875  {
19876  InFile.close();
19877  Utilities->CallLogPop(2198);
19878  return(false);
19879  }
19880  if(!Utilities->CheckFileInt(InFile, 0, 1000000)) // TrainController->AvHoursIntValue
19881  {
19882  InFile.close();
19883  Utilities->CallLogPop(2199);
19884  return(false);
19885  }
19886  if(!Utilities->CheckFileInt(InFile, 0, 1000000)) // number of train failures
19887  {
19888  InFile.close();
19889  Utilities->CallLogPop(2200);
19890  return(false);
19891  }
19892  // now check any failed trains along with their OriginalPowerAtRail values
19893  Utilities->CheckFileString(InFile); // discard "***Failed Trains***"
19894  int IDVal;
19895  if(!Utilities->CheckAndReadFileInt(InFile, -1, 1000000, IDVal)) // train ID or -1 for no more failed trains,
19896  {
19897  InFile.close();
19898  Utilities->CallLogPop(2201);
19899  return(false);
19900  }
19901  double PowerDouble;
19902  while(IDVal != -1)
19903  {
19904  Utilities->CheckFileDouble(InFile); // original power
19905  if(!Utilities->CheckAndReadFileInt(InFile, -1, 1000000, IDVal))
19906  {
19907  InFile.close();
19908  Utilities->CallLogPop(2202);
19909  return(false);
19910  }
19911  }
19912  }
19913  InFile.close();
19914  }
19915  else
19916  {
19917  InFile.close();
19918  Utilities->CallLogPop(1293);
19919  return(false);
19920  }
19921  Utilities->CallLogPop(1294);
19922  return(true);
19923 }
19924 
19925 // ---------------------------------------------------------------------------
19926 
19927 void TInterface::LoadPerformanceFile(int Caller, std::ifstream &InFile)
19928 // Note that the file integrity has already been checked using CheckPerformanceFile
19929 {
19930  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPerformanceFile");
19931  AnsiString TempString = "", Line1 = "", Line2 = "", Line3 = "", Line4 = "", Line5 = "";
19932  char *Buffer = new char[1000];
19933  char TempChar;
19934 
19935  InFile.get(TempChar); // '\n'
19936  InFile.getline(Buffer, 1000);
19937  TempString = AnsiString(Buffer);
19938  if(TempString == "***End of performance file***") //added at v2.10.0
19939  {
19940  Display->PerformanceLog(17, "Performance Log\nRailway: " + RailwayTitle + "\nTimetable: " + TimetableTitle + "\nStart Time: " +
19941  TrainController->TimetableStartTime.FormatString("hh:nn"));
19942  }
19943  else
19944  {
19945  while(TempString != "***End of performance file***")
19946  {
19947  PerformanceLogBox->Lines->Add(TempString);
19948  Utilities->PerformanceFile << TempString.c_str() << '\n';
19949  InFile.getline(Buffer, 1000);
19950  TempString = AnsiString(Buffer);
19951  }
19952  }
19953  delete[] Buffer;
19954  Utilities->CallLogPop(1295);
19955 }
19956 
19957 // ---------------------------------------------------------------------------
19958 
19959 bool TInterface::CheckPerformanceFile(int Caller, std::ifstream &InFile)
19960 {
19961  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPerformanceFile");
19962  AnsiString TempString = "";
19963  char TempChar;
19964 
19965  InFile.get(TempChar);
19966  if(TempChar != '\n')
19967  {
19968  Utilities->CallLogPop(1296);
19969  return(false);
19970  }
19971  if(!Utilities->CheckAndReadFileString(InFile, TempString))
19972  {
19973  Utilities->CallLogPop(1297);
19974  return(false);
19975  }
19976  while(TempString != "***End of performance file***")
19977  {
19978  if(!Utilities->CheckAndReadFileString(InFile, TempString))
19979  {
19980  Utilities->CallLogPop(1298);
19981  return(false);
19982  }
19983  }
19984  Utilities->CallLogPop(1299);
19985  return(true);
19986 }
19987 
19988 // ---------------------------------------------------------------------------
19989 
19990 void TInterface::SavePerformanceFile(int Caller, std::ofstream &OutFile)
19991 {
19992  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePerformanceFile");
19993  AnsiString Text = PerformanceLogBox->Text;
19994 
19995  while(Text != "")
19996  {
19997  AnsiString OneLine = Text.SubString(1, Text.Pos('\x0D'));
19998  while((OneLine.Length() > 0) && OneLine[OneLine.Length()] < ' ')
19999  {
20000  OneLine.SetLength(OneLine.Length() - 1); // get rid of trailing control characters
20001  }
20002  Text = Text.SubString(Text.Pos('\x0D'), Text.Length());
20003  while((Text.Length() > 0) && Text[1] < ' ')
20004  {
20005  Text = Text.SubString(2, (Text.Length() - 1)); // get rid of leading control characters
20006  }
20007  OutFile << OneLine.c_str() << '\n';
20008  }
20009  Utilities->CallLogPop(1300);
20010 }
20011 
20012 // ---------------------------------------------------------------------------
20013 
20015 {
20016  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteButtonsInfoCaptionAndRouteNotStarted");
20017  if(EveryPrefDir->PrefDirSize() > 0)
20018  {
20019  if(AutoSigsFlag)
20020  {
20021  AutoSigsButton->Enabled = false;
20022  SigPrefConsecButton->Enabled = true;
20023  SigPrefNonConsecButton->Enabled = true;
20024  UnrestrictedButton->Enabled = true;
20025  InfoPanel->Visible = true;
20026  if(Level2OperMode == PreStart)
20027  {
20028  InfoPanel->Caption = "PRE-START: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
20029  }
20030  else
20031  {
20032  InfoPanel->Caption = "OPERATING: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
20033  }
20034  InfoCaptionStore = InfoPanel->Caption;
20035  }
20036  else if(PreferredRoute & ConsecSignalsRoute) // added at v2.7.0, was just ConsecSignalsRoute
20037  {
20038  AutoSigsButton->Enabled = true;
20039  SigPrefConsecButton->Enabled = false;
20040  SigPrefNonConsecButton->Enabled = true;
20041  UnrestrictedButton->Enabled = true;
20042  InfoPanel->Visible = true;
20043  if(Level2OperMode == PreStart)
20044  {
20045  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
20046  }
20047  else
20048  {
20049  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
20050  }
20051  InfoCaptionStore = InfoPanel->Caption;
20052  }
20053  else if(PreferredRoute&!ConsecSignalsRoute) // added at v2.7.0
20054  {
20055  AutoSigsButton->Enabled = true;
20056  SigPrefConsecButton->Enabled = true;
20057  SigPrefNonConsecButton->Enabled = false;
20058  UnrestrictedButton->Enabled = true;
20059  InfoPanel->Visible = true;
20060  if(Level2OperMode == PreStart)
20061  {
20062  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
20063  }
20064  else
20065  {
20066  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
20067  }
20068  InfoCaptionStore = InfoPanel->Caption;
20069  }
20070  else
20071  {
20072  AutoSigsButton->Enabled = true;
20073  SigPrefConsecButton->Enabled = true;
20074  SigPrefNonConsecButton->Enabled = true;
20075  UnrestrictedButton->Enabled = false;
20076  InfoPanel->Visible = true;
20077  if(Level2OperMode == PreStart)
20078  {
20079  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
20080  }
20081  else
20082  {
20083  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
20084  }
20085  InfoCaptionStore = InfoPanel->Caption;
20086  }
20087  }
20088  else
20089  {
20090  AutoSigsButton->Enabled = false;
20091  SigPrefConsecButton->Enabled = false;
20092  SigPrefNonConsecButton->Enabled = false;
20093  UnrestrictedButton->Enabled = false;
20094  InfoPanel->Visible = true;
20095  if(Level2OperMode == PreStart)
20096  {
20097  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
20098  }
20099  else
20100  {
20101  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
20102  }
20103  InfoCaptionStore = InfoPanel->Caption;
20104  }
20106  {
20107  RouteCancelButton->Enabled = true;
20108  }
20109  else
20110  {
20111  RouteCancelButton->Enabled = false;
20112  }
20114  AutoRouteStartMarker->PlotOriginal(37, Display); // so start marker will replot if had selected start before pause & zoom
20117  Utilities->CallLogPop(1301);
20118 }
20119 
20120 // ---------------------------------------------------------------------------
20121 
20123 {
20124  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetPausedOrZoomedInfoCaption");
20125  if(Display->ZoomOutFlag)
20126  {
20127  InfoPanel->Visible = true;
20128  InfoPanel->Caption = "Left click screen to zoom in at that position";
20129  }
20130  else if(Level2OperMode == Paused)
20131  {
20132  InfoPanel->Visible = true;
20133  InfoPanel->Caption = "PAUSED: Railway state changes disabled";
20134  }
20135 // otherwise do nothing
20136  Utilities->CallLogPop(1302);
20137 }
20138 
20139 // ---------------------------------------------------------------------------
20140 
20141 void TInterface::DisableRouteButtons(int Caller)
20142 {
20143  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DisableRouteButtons");
20144  RouteCancelButton->Enabled = false;
20145  AutoSigsButton->Enabled = false;
20146  SigPrefConsecButton->Enabled = false;
20147  SigPrefNonConsecButton->Enabled = false;
20148  UnrestrictedButton->Enabled = false;
20149  Utilities->CallLogPop(1303);
20150 }
20151 
20152 // ---------------------------------------------------------------------------
20153 
20155 // no need for call logging as already failed
20156 {
20157 /*
20158  In order to reload as a session file:
20159 
20160  NB: Don't change it to a .txt file, as the '\0' characters [shown as a small square in wordpad] will be changed to spaces if it is subsequently saved
20161  strip out:-
20162 
20163  [since adding user graphics after prefdirs need to take this into account]
20164 
20165  up to but excluding ***Interface***
20166  from & including ***ConstructPrefDir PrefDirVector***
20167  to but excluding ***PrefDirs***
20168  if there is a single line ***UserGraphics*** delete it (won't be present if no graphics)
20169  from & including ***ConstructRoute PrefDirVector***
20170  to but excluding ***Routes***
20171  from & including ***ChangingLCVector*** to but excluding ***Timetable*** [if have ***No timetable loaded*** then can't use as a session file]
20172  from & including ***No editing timetable*** or ***Editing timetable - [title]***
20173  to but excluding ***TimetableClock***
20174 
20175  need to think more about the later additions & include those but not the v2.8.0 additions (& ensure save trains & perf file)
20176 
20177  and save as a .ssn file.
20178 
20179  In order to load as a railway file: Note if error involves cut/copy etc with prefdirs then need to drop the check of CheckCount
20180 
20181  NB: Don't change it to a .txt file, as the '\0' characters will be changed to spaces if it is subsequently saved
20182 
20183  note or copy the version information at the top of the file
20184  copy the two numbers on rows 7 & 8 below ***Interface*** (i.e ***Interface*** = row 0) on their own lines immediately after the ***Track*** line (these become DisplayOffsetH & V)
20185  strip out up to but excluding ***Track*** - this is needed to keep the \0 entry at end of ***Track*** [shown as a small square in wordpad]
20186  add the version number either before or instead of ***Track***, ensuring that the \0 is retained
20187  the next line after the two insertions should contain the number of active elements.
20188  strip out ***Text*** including the \0
20189  strip out from & including ***ConstructPrefDir PrefDirVector*** to & including ***PrefDirs*** (and the \0's)
20190  strip out ***UserGraphics*** including the \0 <--this is missing
20191  strip out from & including the number preceding ***ConstructRoute SearchVector*** to the end of the file
20192  the last entry should be '************NUL CR LF' (after all the pref dirs)
20193  rename as .dev or .rly file
20194 
20195  BUT - note that signals (and points, though they won't show) will be set as they were left. To reset to red, load a suitable timetable & select
20196  'Operate' then 'Exit operation'.
20197 */
20198 
20199 /*
20200  In order to extract a timetable:
20201 
20202  NB: Don't change it to a .txt file, as the '\0' characters will be changed to spaces if it is subsequently saved
20203 
20204  set wordwrap to window on
20205  strip out all to and including ***Timetable*** or ***Editing timetable.... depending which is to be saved
20206  ensure any text before start time ends with /0, otherwise don't need the \0
20207  strip out all after the final /0 immediately before ***End*** or ***End of timetable***, but ensure leave the final /0
20208  save as a .ttb file
20209 */
20210 
20211  Screen->Cursor = TCursor(-11); // Hourglass;
20212  AnsiString ErrorFileStr = CurDir + "\\errorlog.err";
20213  std::ofstream ErrorFile(ErrorFileStr.c_str());
20214 
20215  if(!(ErrorFile.fail()))
20216  {
20217 // save mouse position relative to mainscreen
20218  int ScreenX = Mouse->CursorPos.x - MainScreen->ClientOrigin.x;
20219  int ScreenY = Mouse->CursorPos.y - MainScreen->ClientOrigin.y;
20220  AnsiString MouseStr = "Posx: " + AnsiString(ScreenX) + "; Posy: " + AnsiString(ScreenY);
20221  Utilities->SaveFileString(ErrorFile, MouseStr);
20222  Utilities->SaveFileInt(ErrorFile, MissedTicks);
20223  Utilities->SaveFileInt(ErrorFile, TotalTicks);
20224 
20225 // save call stack
20226  Utilities->SaveFileString(ErrorFile, "***Call stack***");
20227  for(unsigned int x = 0; x < Utilities->CallLog.size(); x++)
20228  {
20229  AnsiString Item = Utilities->CallLog.at(x);
20230  ErrorFile << Item.c_str() << '\n';
20231  }
20232 // save event log
20233  Utilities->SaveFileString(ErrorFile, "***Event log***");
20234  for(unsigned int x = 0; x < Utilities->EventLog.size(); x++)
20235  {
20236  AnsiString Item = Utilities->EventLog.at(x);
20237  ErrorFile << Item.c_str() << '\n';
20238  }
20239 // save interface
20240  Utilities->SaveFileString(ErrorFile, "***Interface***");
20241  SaveInterface(1, ErrorFile);
20242 // save track elements
20243  Utilities->SaveFileString(ErrorFile, "***Track***");
20244  if(Track->UserGraphicVector.empty())
20245  {
20246  Track->SaveTrack(2, ErrorFile, false); // false for no graphics (**Active elements** saved as marker)
20247  }
20248  else
20249  {
20250  Track->SaveTrack(12, ErrorFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
20251  }
20252 // save text elements
20253  Utilities->SaveFileString(ErrorFile, "***Text***");
20254  TextHandler->SaveText(3, ErrorFile);
20255 // save ConstructPrefDir PrefDirVector elements
20256  Utilities->SaveFileString(ErrorFile, "***ConstructPrefDir PrefDirVector***");
20257  ConstructPrefDir->SavePrefDirVector(7, ErrorFile);
20258 // save ConstructPrefDir SearchVector elements
20259  Utilities->SaveFileString(ErrorFile, "***ConstructPrefDir SearchVector***");
20260  ConstructPrefDir->SaveSearchVector(0, ErrorFile);
20261 // save EveryPrefDir elements
20262  Utilities->SaveFileString(ErrorFile, "***PrefDirs***");
20263  EveryPrefDir->SavePrefDirVector(3, ErrorFile);
20264  if(!Track->UserGraphicVector.empty())
20265  {
20266  // save user graphics
20267  Utilities->SaveFileString(ErrorFile, "***UserGraphics***");
20268  Track->SaveUserGraphics(3, ErrorFile);
20269  }
20270 // save ConstructRoute PrefDirVector
20271  Utilities->SaveFileString(ErrorFile, "***ConstructRoute PrefDirVector***");
20272  ConstructRoute->SavePrefDirVector(4, ErrorFile);
20273 // save ConstructRoute SearchVector
20274  Utilities->SaveFileString(ErrorFile, "***ConstructRoute SearchVector***");
20275  ConstructRoute->SaveSearchVector(1, ErrorFile);
20276 // save AllRoutes
20277  Utilities->SaveFileString(ErrorFile, "***Routes***");
20278  AllRoutes->SaveRoutes(1, ErrorFile);
20279 // save LockedRoutes
20280  Utilities->SaveFileString(ErrorFile, "***Locked routes***");
20282 // save ContinuationAutoSigEntries
20283  Utilities->SaveFileString(ErrorFile, "***ContinuationAutoSigEntries***");
20285 // save BarriersDownVector
20286  Utilities->SaveFileString(ErrorFile, "***BarriersDownVector***");
20287  Track->SaveSessionBarriersDownVector(1, ErrorFile);
20288 // save ChangingLCVector
20289  Utilities->SaveFileString(ErrorFile, "***ChangingLCVector***");
20290  Track->SaveChangingLCVector(0, ErrorFile);
20291 // save loaded timetable
20292  if(TimetableTitle == "")
20293  {
20294  Utilities->SaveFileString(ErrorFile, "***No timetable loaded***");
20295  }
20296  else
20297  {
20298  Utilities->SaveFileString(ErrorFile, "***Timetable***");
20299  if(!(SaveTimetableToSessionFile(1, ErrorFile, ErrorFileStr)))
20300  {
20301  Utilities->SaveFileString(ErrorFile, "***Loaded timetable failed to save***");
20302  }
20303  }
20304 // save editing timetable
20305  if(CreateEditTTTitle == "")
20306  {
20307  Utilities->SaveFileString(ErrorFile, "***No editing timetable***");
20308  }
20309  else
20310  {
20311  Utilities->SaveFileString(ErrorFile, "***Editing timetable - " + CreateEditTTTitle + "***");
20312  if(!(SaveTimetableToErrorFile(1, ErrorFile, ErrorFileStr, CreateEditTTFileName)))
20313  {
20314  Utilities->SaveFileString(ErrorFile, "***Editing timetable failed to save***");
20315  }
20316  }
20317 // save TimetableClock
20318  Utilities->SaveFileString(ErrorFile, "***TimetableClock***");
20319  Utilities->SaveFileDouble(ErrorFile, double(TrainController->TTClockTime));
20320 // save trains
20321  Utilities->SaveFileString(ErrorFile, "***Trains***");
20322  TrainController->SaveSessionTrains(1, ErrorFile);
20323 // save performance file
20324  Utilities->SaveFileString(ErrorFile, "***Performance file***");
20325  SavePerformanceFile(1, ErrorFile);
20326  Utilities->SaveFileString(ErrorFile, "***End of performance file***");
20327 // addition at v2.4.1 to save TrainController->AvHoursIntValue + any future additions
20328  Utilities->SaveFileString(ErrorFile, "***Additions after v2.3.1***");
20331  Utilities->SaveFileString(ErrorFile, "***Failed Trains***");
20332  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
20333  {
20335  {
20338  }
20339  }
20340  Utilities->SaveFileInt(ErrorFile, -1); // marker for end of failed trains
20341  Utilities->SaveFileString(ErrorFile, "End of file at v2.4.1");
20342 // end of v2.4.1 addition
20343 
20344 // added at v2.7.0 - extras saved later in session file (added at v2.9.2)
20346  Utilities->SaveFileString(ErrorFile, "End of file at v2.7.0");
20347 // end of v2.7.0 addition
20348 
20349 // added at v2.9.1
20355  Utilities->SaveFileString(ErrorFile, "End of v2.9.1 additions"); //changed from '2.9.0' at v2.9.2
20356 // end of v2.9.1 additions
20357 
20358 // addition at v2.8.0 in case of clipboard errors <-- keep at end of file as not wanted in a reconstructed session file
20359  Utilities->SaveFileInt(ErrorFile, SelectBitmap->Height); // extras for new clipboard functions
20360  Utilities->SaveFileInt(ErrorFile, SelectBitmap->Width);
20361  Utilities->SaveFileInt(ErrorFile, SelectBitmapHLoc); // paste location
20362  Utilities->SaveFileInt(ErrorFile, SelectBitmapVLoc);
20363  Utilities->SaveFileInt(ErrorFile, SelectRect.left); // original selection location
20364  Utilities->SaveFileInt(ErrorFile, SelectRect.top);
20365  Utilities->SaveFileInt(ErrorFile, SelectRect.right);
20366  Utilities->SaveFileInt(ErrorFile, SelectRect.bottom);
20367  Utilities->SaveFileString(ErrorFile, "End of clipboard additions");
20368 // end of 2.8.0 addition
20369  ErrorFile.close();
20370  }
20371  else
20372  {
20373  TrainController->StopTTClockMessage(6, "Error file failed to open, error log won't be saved.");
20374  }
20375  Screen->Cursor = TCursor(-2); // Arrow
20376 }
20377 
20378 // ---------------------------------------------------------------------------
20379 
20380 void TInterface::SaveTempTimetableFile(int Caller, AnsiString InFileName)
20381 // the .ttb section is delimited by '\n' followed by "***End***"
20382 // first create a .ttb file in the working folder exactly like the original
20383 
20384 // Note: this type of file use failed when used to resave timetable.tmp from temp .ttb file, but changed that to avoid so many rapid
20385 // file actions in quick succession & been OK since then, but nevertheless keep the 10 retries before giving message to be on safe side
20386 {
20387  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTempTimetableFile");
20388  if((TempTTFileName != "") && FileExists(TempTTFileName))
20389  {
20390  DeleteFile(TempTTFileName);
20391  }
20392  int TempTTFileNumber = 0;
20393 
20394  while(FileExists(CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp"))
20395  {
20396  TempTTFileNumber++;
20397  }
20398  TempTTFileName = CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp";
20399  int InHandle = FileOpen(InFileName, fmOpenRead);
20400  int Count = 0;
20401 
20402  while(InHandle < 0) // sometimes fails, have 10 retries before giving message
20403  {
20404  InHandle = FileOpen(InFileName, fmOpenRead);
20405  Count++;
20406  Delay(2, 50); // 50mSec delay between tries
20407  if(Count > 10)
20408  {
20409  ShowMessage("Failed to open timetable file, make sure it's spelled correctly, it exists and isn't open in another application");
20410  Utilities->CallLogPop(1400);
20411  return;
20412  }
20413  }
20414  int OutHandle = FileCreate(TempTTFileName);
20415 
20416  Count = 0;
20417  while(OutHandle < 0) // sometimes fails, have 10 retries before giving message
20418  {
20419  OutHandle = FileCreate(TempTTFileName);
20420  Count++;
20421  Delay(3, 50); // 50mSec delay between tries
20422  if(Count > 10)
20423  {
20424  ShowMessage("Failed to save temporary timetable file, sessions can't be saved - try again, may only be a temporary problem");
20425  FileClose(InHandle);
20426  Utilities->CallLogPop(1401);
20427  return;
20428  }
20429  }
20430  int CountIn, CountOut;
20431  char *Buffer = new char[10000]; // can't use LoadFileString as that expects a '\0' delimiter
20432 
20433  while(true)
20434  {
20435  CountIn = FileRead(InHandle, Buffer, 10000);
20436  CountOut = FileWrite(OutHandle, Buffer, CountIn);
20437  if(CountOut != CountIn)
20438  {
20439  ShowMessage("Error in writing to the temporary timetable file, sessions can't be saved - try again, may only be a temporary problem");
20440  delete[] Buffer;
20441  FileClose(InHandle);
20442  FileClose(OutHandle);
20443  Utilities->CallLogPop(1402);
20444  return;
20445  }
20446  if(CountIn < 10000)
20447  {
20448  break;
20449  }
20450  }
20451  delete[] Buffer;
20452  FileClose(InHandle);
20453  FileClose(OutHandle);
20454  Utilities->CallLogPop(1403);
20455 }
20456 
20457 // ---------------------------------------------------------------------------
20458 
20459 void TInterface::SetTrackLengths(int Caller, int Distance, int SpeedLimit) // Distance & SpeedLimit are -1 for no change to that parameter
20460 /*
20461  Rules: Platforms are fixed length elements of 100m and aren't changed - no, see note below. Variable length elements can't be less than 20m.
20462  above changed in v2.4.0 to be variable as other track, but if <50m or >200m a warning is given
20463 
20464  Enter with DistanceVector containing the PrefDir to be set, Distance containing the required sum of all element lengths,
20465  and SpeedLimit containing the speed limit. If either of these is -1 (can be -1 separately) then no change is to be made to it.
20466  Return for an empty DistanceVector. Deal first with a single element in the vector, giving a message if there is a platform there.
20467  Now set exit link position (XLinkPos) value for the first element in DistanceVector by checking which link connects to the second
20468  element in the vector, and give a warning message if fail to find it. Now have to make two passes through the vector, firstly to
20469  sum the fixed lengths, count the number of variable length elements and set the speed limit, and secondly to set the lengths.
20470  Firstly store the first XLinkPos so don't have to recalculate it for the second pass. On the first pass examine each element,
20471  incrementing the variable element count or summing the fixed length count as go along, and setting the speed limits providing
20472  SpeedLimit isn't -1. If Distance was -1 then still go through but don't count anything, just set the speed limits. Recalculate
20473  the next XLinkPos for each succeeding element.
20474  After the first pass return if Distance was -1 as in that case have now finished. Otherwise check if the distance to be set is less than
20475  the minimum possible within the rules, and if so give a message and return. Also give a warning message if there aren't any variable length
20476  elements. Now enter the second pass. In this the length of each variable element is set to int(RemainingDistance/RemainingVarElements) and
20477  fixed length elements are ignored. After each variable length element is set the RemainingDistance and RemainingVarElements are recalculated
20478  ready for the next setting. In this way there is never more than 1 difference between any two variable length elements and the total
20479  distance sums exactly to the value required. A check is made after every variable length element has been set to see whether RemainingDistance
20480  and RemainingVarElements are zero, and if they don't reach zero together (which they should after the last variable length element has
20481  been set), an error message is given.
20482 */
20483 
20484 {
20485  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLengths," + AnsiString(Distance) + "," + AnsiString(SpeedLimit));
20486  bool FoundFlag;
20487 
20488 // ResetDistanceElements(4);
20489  if(ConstructPrefDir->PrefDirSize() == 0)
20490  {
20491  Utilities->CallLogPop(608);
20492  return;
20493  }
20494 // must have PrefDir size of at least 2
20495 
20496 // first pass to count number of variable length elements, sum fixed lengths & set speed limit
20497 // for version in v2.4.0 have no fixed length elements but leave code as is as much as possible
20498  int VarElements = 0; // FixedLength = 0; drop this in v2.4.0
20499  bool NamedLocPresent = false;
20500 
20501  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
20502  {
20503  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(167, x);
20504  TTrackElement & TE = Track->TrackElementAt(34, Track->GetVectorPositionFromTrackMap(28, PrefDirElement.HLoc, PrefDirElement.VLoc, FoundFlag));
20505  if(!FoundFlag)
20506  {
20507  throw Exception("Error - failed to find track element at " + AnsiString(TE.HLoc) + " & " + AnsiString(TE.VLoc) + " in SetLengths");
20508  }
20509  if((Distance != -1) && (!Track->IsPlatformOrNamedNonStationLocationPresent(2, TE.HLoc, TE.VLoc)))
20510  {
20511  VarElements++;
20512  }
20513  else if((Distance != -1) && (Track->IsPlatformOrNamedNonStationLocationPresent(3, TE.HLoc, TE.VLoc)))
20514  {
20515  VarElements++; // added in v2.4.0 for no fixed elements
20516  NamedLocPresent = true;
20517 // FixedLength+= DefaultTrackLength; dropped in v2.4.0 for no fixed elements
20518  }
20519  if((PrefDirElement.GetELinkPos() < 2) && (PrefDirElement.GetXLinkPos() < 2)) // could be points
20520  {
20521  if(SpeedLimit != -1)
20522  {
20523  TE.SpeedLimit01 = SpeedLimit;
20524  }
20525  }
20526  else
20527  {
20528  if(SpeedLimit != -1)
20529  {
20530  TE.SpeedLimit23 = SpeedLimit;
20531  }
20532  }
20533  }
20534  if(Distance == -1) // can't return before this as need to set speed limits
20535  {
20536  Utilities->CallLogPop(612);
20537  return;
20538  }
20539  if((NamedLocPresent) && (VarElements > 0) && ((Distance / VarElements) < 50)) // these two additions are for in v2.4.0
20540  {
20541  if(!TooShortMessageSentFlag) //added at v2.9.1
20542  {
20543  ShowMessage("Note: Named location elements are quite short. If they are too short the simulation might be too unrealistic.\n\nThis message will not be shown again.");
20544  TooShortMessageSentFlag = true; //added at v2.9.1
20545  }
20546  }
20547  if((NamedLocPresent) && (VarElements > 0) && ((Distance / VarElements) > 200))
20548  {
20549  if(!TooLongMessageSentFlag) //added at v2.9.1
20550  {
20551  ShowMessage("Note: Named location elements are quite long. If they are too long the simulation might be too unrealistic.\n\nThis message will not be shown again.");
20552  TooLongMessageSentFlag = true; //added at v2.9.1
20553  }
20554  }
20555 /* if(NamedLocPresent) as was
20556  {
20557  ShowMessage("Named location lengths won't be changed");
20558  }
20559 */
20560 
20561  if((VarElements * 20) > Distance) // removed '+ FixedLength'
20562  {
20563  ShowMessage("Required distance is less than the minimum, will set each element to the minimum (20m)");
20564  Distance = (VarElements * 20); // removed '+ FixedLength'
20565  }
20566  if(VarElements == 0)
20567  {
20568 // ShowMessage("Unable to set distance as all elements are of fixed length"); as was
20569  ShowMessage("No elements selected"); // probably don't need this but include for safety
20570  Utilities->CallLogPop(613);
20571  return;
20572  }
20573 // second pass, set variable lengths
20574  int RemainingDistance = Distance, RemainingVarElements = VarElements, NextLength = RemainingDistance / VarElements; // removed ' - FixedLength'
20575 
20576  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
20577  {
20578  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(168, x);
20579  TTrackElement & TE = Track->TrackElementAt(35, Track->GetVectorPositionFromTrackMap(29, PrefDirElement.HLoc, PrefDirElement.VLoc, FoundFlag));
20580 // if(!Track->IsPlatformOrNamedNonStationLocationPresent(4, TE.HLoc, TE.VLoc)) //variable lengths dropped in v2.4.0
20581 // {
20582  if(NextLength < 20)
20583  {
20584  NextLength = 20; // added for safety
20585  }
20586  if(TE.TrackType == Points)
20587  {
20588  if((PrefDirElement.GetELinkPos() == 1) || (PrefDirElement.GetXLinkPos() == 1))
20589  {
20590  TE.Length01 = NextLength;
20591  }
20592  else
20593  {
20594  TE.Length23 = NextLength;
20595  }
20596  }
20597  else
20598  {
20599  if(PrefDirElement.GetELinkPos() < 2)
20600  {
20601  TE.Length01 = NextLength;
20602  }
20603  else
20604  {
20605  TE.Length23 = NextLength;
20606  }
20607  }
20608  RemainingDistance -= NextLength;
20609  RemainingVarElements--;
20610  if(RemainingVarElements > 0)
20611  {
20612  NextLength = RemainingDistance / RemainingVarElements;
20613  }
20614  else
20615  {
20616  NextLength = 20;
20617  }
20618 /* removed these as using integer division & that sometimes problematic. None of these errors ever reported but be safe
20619  if((RemainingDistance == 0) && (RemainingVarElements != 0))
20620  {
20621  throw Exception("Error RemainingDistance == 0 & RemainingVarElements != 0");
20622  }
20623  if((RemainingDistance != 0) && (RemainingVarElements == 0))
20624  {
20625  throw Exception("Error RemainingDistance != 0 & RemainingVarElements == 0");
20626  }
20627 */
20628 // }
20629  }
20630  Utilities->CallLogPop(614);
20631 }
20632 
20633 // ---------------------------------------------------------------------------
20634 
20635 void TInterface::SaveAsSubroutine(int Caller)
20636 {
20637  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveAsSubroutine");
20639  {
20640  ShowMessage("Nothing to save!");
20641  }
20642  else
20643  {
20644  if(Track->IsReadyForOperation(false))
20645  {
20646  SaveRailwayDialog->Filter = "Development file (*.dev)|*.dev|Railway file (*.rly)|*.rly";
20647  }
20648  else
20649  {
20650  SaveRailwayDialog->Filter = "Development file (*.dev)|*.dev";
20651  }
20652  if(SaveRailwayDialog->Execute())
20653  {
20654  if(SaveRailwayDialog->InitialDir != TPath::GetDirectoryName(SaveRailwayDialog->FileName)) // new at v2.6.0 to retain a new directory
20655  {
20656  SaveRailwayDialog->InitialDir = TPath::GetDirectoryName(SaveRailwayDialog->FileName);
20657  LoadRailwayDialog->InitialDir = TPath::GetDirectoryName(SaveRailwayDialog->FileName);
20658  }
20659  Screen->Cursor = TCursor(-11); // Hourglass;
20660  TrainController->LogEvent("Save " + SaveRailwayDialog->FileName);
20661  AnsiString Extension = "";
20662  if(SaveRailwayDialog->FileName.Length() > 2)
20663  {
20664  Extension = AnsiString(SaveRailwayDialog->FileName).SubString(AnsiString(SaveRailwayDialog->FileName).Length() - 2, 3).UpperCase();
20665  }
20666  if((Extension == "DEV") || (Track->IsReadyForOperation(true) && (Extension == "RLY"))) // give duplicated location name message if appropriate
20667  {
20668  std::ofstream VecFile(AnsiString(SaveRailwayDialog->FileName).c_str());
20669  if(!(VecFile.fail()))
20670  {
20674  // save track elements
20675  if(Track->UserGraphicVector.empty())
20676  {
20677  Track->SaveTrack(1, VecFile, false); // false for no graphics (**Active elements** saved as marker)
20678  }
20679  else
20680  {
20681  Track->SaveTrack(13, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
20682  }
20683  // save text elements
20684  TextHandler->SaveText(1, VecFile);
20685  // save PrefDir elements
20686  EveryPrefDir->SavePrefDirVector(1, VecFile);
20687  if(!Track->UserGraphicVector.empty())
20688  {
20689  // save user graphics
20690  Track->SaveUserGraphics(4, VecFile);
20691  }
20692  VecFile.close();
20693  SavedFileName = SaveRailwayDialog->FileName; // includes the full PrefDir
20694  if(SavedFileName != "") // shouldn't be "" at this stage but leave in as a safeguard
20695  {
20696  char LastChar = SavedFileName[SavedFileName.Length()];
20697  if((LastChar == 'y') || (LastChar == 'Y'))
20698  {
20699  RlyFile = true;
20700  }
20701  else
20702  {
20703  RlyFile = false;
20704  }
20705  }
20706  else
20707  {
20708  RlyFile = false;
20709  }
20710  FileChangedFlag = false;
20711  for(int x = SaveRailwayDialog->FileName.Length(); x > 0; x--)
20712  {
20713  if(SaveRailwayDialog->FileName[x] == '\\')
20714  {
20715  RailwayTitle = SaveRailwayDialog->FileName.SubString(x + 1, SaveRailwayDialog->FileName.Length() - x - 4);
20716  // TimetableTitle = ""; leave this as is, no need to unload a tt just because saved railway
20717  SetCaption(7);
20718  break;
20719  }
20720  }
20721  Level1Mode = BaseMode;
20722  SetLevel1Mode(13); // to disable the save option
20723  } // if(!(VecFile.fail()))
20724  else
20725  {
20726  ShowMessage("File open failed prior to save");
20727  }
20728  } // else following if(!Track->IsReadyForOperation() && (Extension != "DEV"))
20729  else
20730  {
20731  ShowMessage("Can't save: extension must be either '.dev', or '.rly' with railway ready for operation");
20732  }
20733  Screen->Cursor = TCursor(-2); // Arrow
20734  } // if(SaveRailwayDialog->Execute())
20735 
20736  }
20737  session_api_->dump(); // update session INI file //added at v2.10.0
20738  Utilities->CallLogPop(1546);
20739 }
20740 
20741 // ---------------------------------------------------------------------------
20742 
20743 void TInterface::SetTrackModeEditMenu(int Caller)
20744 {
20745  try
20746  {
20747  // no need for caller or log as only setting values
20748  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrackModeEditMenu");
20749  CutMenuItem->Visible = true;
20750  CopyMenuItem->Visible = true;
20751  FlipMenuItem->Visible = true;
20752  MirrorMenuItem->Visible = true;
20753  RotRightMenuItem->Visible = true;
20754  RotLeftMenuItem->Visible = true;
20755  RotateMenuItem->Visible = true;
20756  PasteMenuItem->Visible = true;
20757  DeleteMenuItem->Visible = true;
20758  SelectLengthsMenuItem->Visible = true;
20759  ReselectMenuItem->Visible = true;
20760  // Application->MessageBox(L"Running SetTrackModeEditMenu", L"Message", MB_OK); //debug check
20761  CutMenuItem->Enabled = false;
20762  CopyMenuItem->Enabled = false;
20763  FlipMenuItem->Enabled = false;
20764  MirrorMenuItem->Enabled = false;
20765  RotRightMenuItem->Enabled = false;
20766  RotLeftMenuItem->Enabled = false;
20767  RotateMenuItem->Enabled = false;
20768  PasteMenuItem->Enabled = false;
20769  EditMenu->Enabled = false;
20770  System::WideChar ValidityBuffer[14];
20771  Clipboard()->GetTextBuf(ValidityBuffer, 14);
20772  ClpBrdValid = AnsiString(ValidityBuffer);
20773  Clipboard()->Close();
20774 
20775  // new section for 2.8.0 in case have valid clipboard from another application
20776  if(!SelectionValid)
20777  {
20778  if(ClpBrdValid == "RlyClpBrdCopy")
20779  {
20780  PasteMenuItem->Enabled = true;
20781  if(Level1Mode == TrackMode)
20782  {
20783  EditMenu->Enabled = true;
20784  }
20785  CopySelected = true;
20786  Track->CopyFlag = true;
20787  // Level1Mode = TrackMode;
20788  }
20789  else if(ClpBrdValid == "RlyClpBrd_Cut")
20790  {
20791  PasteMenuItem->Enabled = true;
20792  if(Level1Mode == TrackMode)
20793  {
20794  EditMenu->Enabled = true;
20795  }
20796  CopySelected = false;
20797  Track->CopyFlag = false;
20798  // Level1Mode = TrackMode;
20799  }
20800  }
20801  // end of new section
20802 
20803  // PasteWithAttributesMenuItem->Enabled = false; //new at v2.2.0 (dropped at 2.4.0 as all pastes are with attributes)
20804  ClpBrdValid = "";
20805  DeleteMenuItem->Enabled = false;
20806  SelectLengthsMenuItem->Enabled = false;
20807  if(SelectionValid)
20808  {
20809  ReselectMenuItem->Enabled = true;
20810  }
20811  else
20812  {
20813  ReselectMenuItem->Enabled = false;
20814  }
20815  SelectBiDirPrefDirsMenuItem->Visible = false;
20816  CheckPrefDirConflictsMenuItem->Visible = false;
20817  CancelSelectionMenuItem->Enabled = true;
20818  SelectMenuItem->Enabled = true;
20819 
20820  if(NoRailway() && (TrackElementPanel->Visible == false)) //added latter condition at v2.10.0 so can use select to add track elements in bulk
20821  {
20822  SelectMenuItem->Enabled = false;
20823  }
20824  else if(Level1Mode == TrackMode)
20825  {
20826  EditMenu->Enabled = true;
20827  }
20828  Utilities->CallLogPop(2273);
20829  }
20830 
20831  catch(const EClipboardException &e) //non-error catch - added at v2.10.0 after SamWainwright access denial error (08/09/21)
20832  //also reported by Bengt on 03/10/21
20833  {
20834  TrainController->LogEvent("EClipboardException in SetTrackModeEditMenu - message = " + e.Message);
20835  Utilities->CallLogPop(2321);
20836  }
20837 }
20838 
20839 // ---------------------------------------------------------------------------
20840 
20842 {
20843  // no need for caller or log as only setting values
20844  EditMenu->Enabled = true;
20845 
20846  CutMenuItem->Visible = false;
20847  CopyMenuItem->Visible = false;
20848  FlipMenuItem->Visible = false;
20849  MirrorMenuItem->Visible = false;
20850  RotRightMenuItem->Visible = false;
20851  RotLeftMenuItem->Visible = false;
20852  RotateMenuItem->Visible = false;
20853  PasteMenuItem->Visible = false;
20854 // PasteWithAttributesMenuItem->Visible = false; //added at v2.2.0 (dropped at 2.4.0 as all pastes are with attributes)
20855  DeleteMenuItem->Visible = false;
20856  SelectLengthsMenuItem->Visible = false;
20857  ReselectMenuItem->Visible = false;
20858 
20859  SelectBiDirPrefDirsMenuItem->Visible = true;
20860  CheckPrefDirConflictsMenuItem->Visible = true;
20861  SelectBiDirPrefDirsMenuItem->Enabled = false;
20862  CheckPrefDirConflictsMenuItem->Enabled = true;
20863  CancelSelectionMenuItem->Enabled = true;
20864  SelectMenuItem->Enabled = true;
20865 }
20866 
20867 // ---------------------------------------------------------------------------
20868 
20869 bool TInterface::NoRailway()
20870 {
20871  return ((Track->NoActiveOrInactiveTrack(5)) && (TextHandler->TextVectorSize(8) == 0) && Track->UserGraphicVector.empty());
20872 }
20873 
20874 // ---------------------------------------------------------------------------
20875 
20877 {
20878  SelectRect.left = 0;
20879  SelectRect.right = 0;
20880  SelectRect.top = 0;
20881  SelectRect.bottom = 0;
20882 }
20883 
20884 // ---------------------------------------------------------------------------
20885 
20886 bool TInterface::EraseLocationNameText(int Caller, AnsiString Name, int &HPos, int &VPos)
20887 {
20888  // return position of erased name in HPos & VPos, return true for found & erased
20889  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationNameText," + Name);
20890  bool TextFound = false;
20891 
20892 // if(Track->LocationNameMultiMap.find(Name) == Track->LocationNameMultiMap.end()) {} //name not in LocationNameMultiMap, so don't erase from TextVector //condition dropped at v1.1.4 because of change in EnterLocationNames
20893 /* else */ if(TextHandler->FindText(0, Name, HPos, VPos))
20894  {
20895  if(TextHandler->TextErase(4, HPos, VPos, Name))
20896  {
20897  ;
20898  } // condition not used
20899 
20900  TextFound = true;
20901  }
20902  Utilities->CallLogPop(1956);
20903  return(TextFound);
20904 }
20905 
20906 // ---------------------------------------------------------------------------
20907 
20908 void TInterface::AddLocationNameText(int Caller, AnsiString Name, int HPos, int VPos, bool UseEnteredPosition)
20909 {
20910  if(Name == "")
20911  {
20912  return;
20913  }
20914  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddLocationNameText," + Name + "," + AnsiString(HPos) + "," +
20915  AnsiString(VPos) + "," + AnsiString((short)UseEnteredPosition));
20916  int VPosHi, VPosLo, TextPosHi, TextPosLo;
20917  TFont *Font = Display->GetFont();
20918 
20919  if(!UseEnteredPosition)
20920  {
20921  if(!Track->FindHighestLowestAndLeftmostNamedElements(0, Name, VPosHi, VPosLo, HPos))
20922  {
20923  Utilities->CallLogPop(1561);
20924  return;
20925  }
20926  int Depth = abs(Font->Height); // Height may be negative - see C++Builder Help file
20927  TextPosHi = VPosHi + 20; // add depth of track element + 4 pixels
20928  TextPosLo = VPosLo - Depth - 4; // reduce by depth of font + 4 pixels
20929  int ScreenPosHi = (Display->DisplayOffsetV * 16) + 576;
20930  int ScreenPosLo = Display->DisplayOffsetV * 16;
20931  if(TextPosLo >= ScreenPosLo)
20932  {
20933  VPos = TextPosLo; // if Lo value on screen then use that - displays above the location
20934  }
20935  else if(TextPosHi < ScreenPosHi)
20936  {
20937  VPos = TextPosHi;
20938  }
20939  else
20940  {
20941  VPos = ScreenPosLo + 288; // if location extends to or beyond height of screen the display in centre of screen
20942  }
20943  }
20944  TTextItem TI(HPos, VPos, Name, Font);
20945 
20946  TI.Font = Font; // may have been changed in constructor when returned as reference
20947  TextHandler->EnterAndDisplayNewText(1, TI, HPos, VPos);
20948  Utilities->CallLogPop(1558);
20949 }
20950 
20951 // ---------------------------------------------------------------------------
20952 
20953 void TInterface::TestFunction() //triggered by Alt Ctrl 4
20954 {
20955  try
20956  {
20957 /*
20958  ShowMessage(
20959  "Interface->Left + Interface->Width " + UnicodeString(Interface->Left + Interface->Width) +
20960  "\nInterface->Left + MainScreen->Left + MainScreen->Width " +
20961  UnicodeString(Interface->Left + MainScreen->Left + MainScreen->Width) +
20962  "\n\nMainScreen->Width " + UnicodeString(MainScreen->Width) +
20963  "\nMainScreen->Height " + UnicodeString(MainScreen->Height) +
20964  "\nMainScreen->Top " + UnicodeString(MainScreen->Top) +
20965  "\nMainScreen->Left " + UnicodeString(MainScreen->Left) +
20966  " Right " + UnicodeString(MainScreen->Width + MainScreen->Left) +
20967  "\n\nInterface->Width " + UnicodeString(Interface->Width) +
20968  "\nInterface->Left " + UnicodeString(Interface->Left) +
20969  "\nInterface->Top " + UnicodeString(Interface->Top) +
20970  "\n\nScreenRightButton->Left " + UnicodeString(ScreenRightButton->Left)
20971  );
20972 */
20973 /*
20974  for(unsigned int x=0; x<TrainController->TrainVector.size(); x++)
20975  {
20976  if((TrainController->TrainVectorAt(-1, x).HeadCode == "2K02") && (!TrainController->TrainVectorAt(-1, x).TrainOnContinuation(-1)))
20977  {
20978  TrainController->TrainVectorAt(-1, x).TrainFailurePending = true;
20979  }
20980  }
20981 */
20982 
20983 // TrainController->TrainVector.at(0).TrainFailurePending = true;
20984 // TrainController->TrainVector.at(0).PowerAtRail = 0.08;
20985 // TrainController->TrainVector.at(0).StoppedWithoutPower = true;
20986 
20987 
20988 // throw Exception("Test error"); //generate an error file
20989 
20990 // ShowMessage("MissedTicks = " + AnsiString(MissedTicks) + "; TotalTicks = " + AnsiString(TotalTicks));
20991 
20992  }
20993  catch(const Exception &e)
20994  {
20995  ErrorLog(114, e.Message);
20996  }
20997 }
20998 
20999 // ---------------------------------------------------------------------------
21000 /*
21001  void TInterface::LoadNormalSignalGlyphs(int Caller) //changed - see below
21002  {
21003  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadNormalSignalGlyphs,");
21004  SpeedButton68->Glyph->LoadFromResourceName(0, "gl68"); SpeedButton69->Glyph->LoadFromResourceName(0, "gl69");
21005  SpeedButton70->Glyph->LoadFromResourceName(0, "gl70"); SpeedButton71->Glyph->LoadFromResourceName(0, "gl71");
21006  SpeedButton72->Glyph->LoadFromResourceName(0, "gl72"); SpeedButton73->Glyph->LoadFromResourceName(0, "gl73");
21007  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74"); SpeedButton75->Glyph->LoadFromResourceName(0, "gl75");
21008  Utilities->CallLogPop(**);
21009  }
21010 
21011  //---------------------------------------------------------------------------
21012 
21013  void TInterface::LoadGroundSignalGlyphs(int Caller) //changed - see below
21014  {
21015  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGroundSignalGlyphs,");
21016  SpeedButton68->Glyph->LoadFromResourceName(0, "bm68grounddblred"); SpeedButton69->Glyph->LoadFromResourceName(0, "bm69grounddblred");
21017  SpeedButton70->Glyph->LoadFromResourceName(0, "bm70grounddblred"); SpeedButton71->Glyph->LoadFromResourceName(0, "bm71grounddblred");
21018  SpeedButton72->Glyph->LoadFromResourceName(0, "bm72grounddblred"); SpeedButton73->Glyph->LoadFromResourceName(0, "gl73grounddblred");
21019  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74grounddblred"); SpeedButton75->Glyph->LoadFromResourceName(0, "bm75grounddblred");
21020  Utilities->CallLogPop(**);
21021  }
21022 */
21023 // ---------------------------------------------------------------------------
21024 void TInterface::LoadNormalSignalGlyphs(int Caller) // changed from the above at v2.3.0 so the signal glyphs change hands
21025 {
21026  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadNormalSignalGlyphs,");
21035  Utilities->CallLogPop(1871);
21036 }
21037 
21038 // ---------------------------------------------------------------------------
21039 
21040 void TInterface::LoadGroundSignalGlyphs(int Caller) // changed from the above at v2.3.0 so the signal glyphs change hands
21041 {
21042  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGroundSignalGlyphs,");
21051  Utilities->CallLogPop(1872);
21052 }
21053 
21054 // ---------------------------------------------------------------------------
21055 
21056 void TInterface::UpdateOperatorActionPanel(int Caller) // new at v2.2.0
21057 // limit it to 20 entries max
21058 {
21059  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UpdateOperatorActionPanel");
21061  {
21062  OAListBox->Clear();
21063  }
21065  // new at v2.2.0
21066  {
21067  Utilities->CallLogPop(2092);
21068  return;
21069  }
21070  AnsiString OpTimeToActDisplay;
21071  AnsiString OpTimeToActString;
21072  AnsiString HeadCode;
21073  float OpTimeToActFloat;
21074  TTrainController::THCandTrainPosParam HCandTrainPosParam;
21075 
21078  {
21079  if(OAListBox->Items->Count >= 20)
21080  {
21081  break;
21082  }
21083  OpTimeToActFloat = TrainController->OpTimeToActMultiMapIterator->first;
21084  HCandTrainPosParam = TrainController->OpTimeToActMultiMapIterator->second;
21085  HeadCode = HCandTrainPosParam.first;
21086  if(OpTimeToActFloat < 0.25) // 15 secs estimated
21087  {
21088  OpTimeToActString = "NOW";
21089  }
21090  else if(OpTimeToActFloat < 1)
21091  {
21092  OpTimeToActString = "<1";
21093  }
21094  else
21095  {
21096  OpTimeToActString = AnsiString(floor(OpTimeToActFloat));
21097  }
21098  if(OpTimeToActFloat < 60)
21099  {
21100  OpTimeToActDisplay = HeadCode + AnsiString('\t') + OpTimeToActString;
21101  OAListBox->Items->Add(OpTimeToActDisplay); // original
21102  }
21104  }
21105  Utilities->CallLogPop(2093);
21106 }
21107 
21108 // ---------------------------------------------------------------------------
21109 
21110 void TInterface::LoadUserGraphic(int Caller) // new at v2.4.0
21111 {
21112  try
21113  {
21114  TrainController->LogEvent("LoadUserGraphic");
21115  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadUserGraphic");
21116  if(LoadUserGraphicDialog->Execute())
21117  {
21118  TrainController->LogEvent("LoadUserGraphic " + LoadUserGraphicDialog->FileName);
21119  SelectedGraphicFileName = AnsiString(LoadUserGraphicDialog->FileName); // SelectedGraphicFileName is a class member
21121  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
21122  if(UGMIt == Track->UserGraphicMap.end()) // i.e. there isn't an entry for that filename so insert one, else take no action
21123  {
21124  UGME.first = SelectedGraphicFileName;
21125  TPicture *PicPtr = new TPicture;
21126  PicPtr->LoadFromFile(SelectedGraphicFileName);
21127  UGME.second = PicPtr;
21128  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
21129  {
21130  throw Exception("Map Insertion Error 1 - UserGraphicMap insertion failure for " + SelectedGraphicFileName);
21131  }
21132  }
21134  SetLevel2TrackMode(65);
21135  }
21136  Utilities->CallLogPop(2191);
21137  }
21138  catch(const EInvalidGraphic &e) //non-error catch
21139  {
21140  ShowMessage(
21141  "Incorrect file format, the file can't be loaded.\nEnsure that the file you want is a valid graphic file with extension .bmp, .gif, .jpg, or .png");
21142  Utilities->CallLogPop(2311);
21143  }
21144  catch(const Exception &e)
21145  {
21146  ErrorLog(215, e.Message);
21147  }
21148 }
21149 
21150 // ---------------------------------------------------------------------------
21151 
21152 void TInterface::LoadClipboard(int Caller) // new at v2.8.0
21153 {
21154  try
21155  {
21156  TrainController->LogEvent("LoadClipboard");
21157  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadClipboard");
21158 
21159  std::wstringstream wss; // used to hold all parameters prior to conversion to a string buffer
21160  if(CopySelected)
21161  {
21162  wss << "RlyClpBrdCopy\n";
21163  }
21164  else
21165  {
21166  wss << "RlyClpBrd_Cut\n";
21167  }
21168 // Load the active & inactive track vectors
21169  for(TTrack::TTrackVectorIterator TTVIt = Track->SelectVector.begin(); TTVIt < Track->SelectVector.end(); TTVIt++)
21170  {
21171  wss << TTVIt->SpeedTag;
21172  wss << '\n'; // inherited int - all FixedTrackPiece parameters implicit in this
21173  for(int AnsLen = 0; AnsLen <= TTVIt->ActiveTrackElementName.Length(); AnsLen++)
21174  {
21175  if((TTVIt->ActiveTrackElementName).c_str()[AnsLen] != '\0')
21176  {
21177  wss << (TTVIt->ActiveTrackElementName).c_str()[AnsLen];
21178  }
21179  else
21180  {
21181  wss << '\n';
21182  }
21183  }
21184  for(int AnsLen = 0; AnsLen <= TTVIt->ElementID.Length(); AnsLen++)
21185  {
21186  if((TTVIt->ElementID).c_str()[AnsLen] != '\0')
21187  {
21188  wss << (TTVIt->ElementID).c_str()[AnsLen];
21189  }
21190  else
21191  {
21192  wss << '\n';
21193  }
21194  }
21195  for(int AnsLen = 0; AnsLen <= TTVIt->LocationName.Length(); AnsLen++)
21196  {
21197  if((TTVIt->LocationName).c_str()[AnsLen] != '\0')
21198  {
21199  wss << (TTVIt->LocationName).c_str()[AnsLen];
21200  }
21201  else
21202  {
21203  wss << '\n';
21204  }
21205  }
21206  wss << TTVIt->CallingOnSet;
21207  wss << '\n';
21208  wss << TTVIt->LCPlotted;
21209  wss << '\n';
21210  wss << TTVIt->TempTrackMarker01;
21211  wss << '\n';
21212  wss << TTVIt->TempTrackMarker23;
21213  wss << '\n';
21214  wss << TTVIt->Attribute;
21215  wss << '\n'; // all ints from here except last which is an enum
21216  wss << TTVIt->Conn[0];
21217  wss << '\n';
21218  wss << TTVIt->Conn[1];
21219  wss << '\n';
21220  wss << TTVIt->Conn[2];
21221  wss << '\n';
21222  wss << TTVIt->Conn[3];
21223  wss << '\n';
21224  wss << TTVIt->ConnLinkPos[0];
21225  wss << '\n';
21226  wss << TTVIt->ConnLinkPos[1];
21227  wss << '\n';
21228  wss << TTVIt->ConnLinkPos[2];
21229  wss << '\n';
21230  wss << TTVIt->ConnLinkPos[3];
21231  wss << '\n';
21232  wss << TTVIt->HLoc;
21233  wss << '\n';
21234  wss << TTVIt->VLoc;
21235  wss << '\n';
21236  wss << TTVIt->Length01;
21237  wss << '\n';
21238  wss << TTVIt->Length23;
21239  wss << '\n';
21240  wss << TTVIt->SpeedLimit01;
21241  wss << '\n';
21242  wss << TTVIt->SpeedLimit23;
21243  wss << '\n';
21244  wss << TTVIt->StationEntryStopLinkPos1;
21245  wss << '\n';
21246  wss << TTVIt->StationEntryStopLinkPos2;
21247  wss << '\n';
21248  wss << TTVIt->TrainIDOnElement;
21249  wss << '\n';
21250  wss << TTVIt->TrainIDOnBridgeTrackPos01;
21251  wss << '\n';
21252  wss << TTVIt->TrainIDOnBridgeTrackPos23;
21253  wss << '\n';
21254  wss << int(TTVIt->SigAspect);
21255  wss << '\n'; // enum
21256  }
21257  wss << "$$$" << '\n'; // send track element end marker
21258 
21259 // Load the text vector
21260 
21261  for(TTextHandler::TTextVectorIterator TTVIt = TextHandler->SelectTextVector.begin(); TTVIt < TextHandler->SelectTextVector.end(); TTVIt++)
21262  {
21263  for(int AnsLen = 0; AnsLen <= TTVIt->TextString.Length(); AnsLen++)
21264  {
21265  if((TTVIt->TextString).c_str()[AnsLen] != '\0')
21266  {
21267  wss << (TTVIt->TextString).c_str()[AnsLen];
21268  }
21269  else
21270  {
21271  wss << '\n';
21272  }
21273  }
21274  wss << TTVIt->HPos;
21275  wss << '\n';
21276  wss << TTVIt->VPos;
21277  wss << '\n';
21278  for(int AnsLen = 0; AnsLen <= AnsiString(TTVIt->Font->Name).Length(); AnsLen++)
21279  {
21280  if(AnsiString(TTVIt->Font->Name).c_str()[AnsLen] != '\0')
21281  {
21282  wss << AnsiString(TTVIt->Font->Name).c_str()[AnsLen];
21283  }
21284  else
21285  {
21286  wss << '\n';
21287  }
21288  }
21289  wss << TTVIt->Font->Size;
21290  wss << '\n';
21291  if((TTVIt->Font->Color < 0) || (TTVIt->Font->Color > 0xFFFFFF)) // if set to any of the special 'windows' colours save it as black
21292  {
21293  wss << "0\n";
21294  }
21295  else
21296  {
21297  wss << int(TTVIt->Font->Color) << '\n';
21298  }
21299  wss << int(TTVIt->Font->Charset) << '\n'; // save as 'int' (would be unsigned char else) so 'n' can act as proper delimiter
21300  wss << TextHandler->GetFontStyleAsInt(1, TTVIt->Font) << '\n';
21301  }
21302  wss << "$$$" << '\n'; // send text item end marker
21303 
21304  //load select dimensions
21305  wss << SelectBitmap->Height;
21306  wss << '\n';
21307  wss << SelectBitmap->Width;
21308  wss << '\n';
21309  wss << SelectRect.left;
21310  wss << '\n';
21311  wss << SelectRect.top;
21312  wss << '\n';
21313  wss << "$$$" << '\n'; // send end of select dimension marker
21314 
21315  //load preferred directions //added at v2.9.0
21316  if(SelectPrefDir->PrefDirSize() > 0) // skip load if empty
21317  {
21318  for(TOnePrefDir::TPrefDirVectorIterator PDVIt = SelectPrefDir->PrefDirVector.begin(); PDVIt < SelectPrefDir->PrefDirVector.end(); PDVIt++)
21319  {
21320  //Note that TrackVector Position won't be valid for a remote paste, it will be reset when pasted, also Conns & ConnLinkPosses set when
21321  //track linked
21322  wss << PDVIt->GetTrackVectorPosition(); //added at v2.9.2 so all 9 of CheckCount properties loaded (SpeedTag loaded from TrackElement at HLoc & VLoc)
21323  wss << '\n';
21324  wss << PDVIt->GetHLoc();
21325  wss << '\n';
21326  wss << PDVIt->GetVLoc();
21327  wss << '\n';
21328  wss << PDVIt->GetELink();
21329  wss << '\n';
21330  wss << PDVIt->GetELinkPos();
21331  wss << '\n';
21332  wss << PDVIt->GetXLink();
21333  wss << '\n';
21334  wss << PDVIt->GetXLinkPos();
21335  wss << '\n';
21336  wss << PDVIt->GetEXNumber();
21337  wss << '\n';
21338  }
21339  }
21340  wss << "$$$" << '\n'; // send pref dir end marker
21341  wss << '\0'; // has to end with NULL
21342 
21343  Clipboard()->Clear(); // clear the clipboard
21344  Clipboard()->SetTextBuf(&(wss.str()[0])); // populate the clipboard
21345  Clipboard()->Close();
21346 
21347  Utilities->CallLogPop(2267);
21348  }
21349 
21350  catch(const EClipboardException &e) //non-error catch - ignore access denials (but only seems to happen with recover), doesn't affect program
21351  {
21352 // Application->MessageBox(L"A clipboard error occurred in loading the clipboard", L"Message", MB_OK);
21353  TrainController->LogEvent("EClipboardException in LoadClipboard - message = " + e.Message);
21354  Utilities->CallLogPop(2312);
21355  }
21356 
21357  catch(const Exception &e)
21358  {
21359  ErrorLog(222, e.Message);
21360  }
21361 
21362 }
21363 
21364 // ---------------------------------------------------------------------------
21365 
21366 void TInterface::RecoverClipboard(int Caller, bool &ValidResult) // new at v2.8.0
21367 {
21368  try
21369  {
21370  TrainController->LogEvent("RecoverClipboard");
21371  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RecoverClipboard");
21372  ValidResult = false;
21373  System::WideChar *SelectVectorBuffer = new System::WideChar[4000000]; // scope for 130 chars per element & 4k resolution (240 x 135 elements)
21374  int StreamSize = 0;
21375  StreamSize = Clipboard()->GetTextBuf(SelectVectorBuffer, 4000000);
21376  Clipboard()->Clear(); // clear it so can't keep pasting same thing as don't permit this in single app
21377  Clipboard()->Close();
21378  if(StreamSize < 14)
21379  {
21380  Utilities->CallLogPop(2270); // ValidResult == false
21381  return;
21382  }
21383  std::wstringstream wss;
21384  wss << SelectVectorBuffer;
21385  ClpBrdValid = AnsiString(SelectVectorBuffer).SubString(1, 13);
21386  PasteMenuItem->Enabled = false;
21387  delete[] SelectVectorBuffer;
21388 
21389  if((ClpBrdValid != AnsiString("RlyClpBrdCopy")) && (ClpBrdValid != AnsiString("RlyClpBrd_Cut")))
21390  {
21391  Utilities->CallLogPop(2268); // ValidResult == false
21392  return;
21393  }
21394  int MarkerCounter = 0; //If ever get a MarkerCounter value well outside expected range it's probably because some text is too long - see comment below
21395  ClpBrdValid = "";
21396  wchar_t LineString[1000]; // should be big enough for any entry, (extended from 100 at v2.9.2) text can be long but hopefully not this long - won't
21397  //recover the clipboard if longer but won't crash. It has to be at least as big as the biggest getline number or the excess will overwrite other variables,
21398  //this was discovered when MarkerCounter suddenly jumped from 1 to nearly 3000000 when Linesting loaded with text ~180 chars long with LineString limited
21399  //to 100 chars
21400 
21401  wss.getline(LineString, 100); // RlyClpBrdCopy or ...Cut - discard it
21402  Track->SelectVector.clear();
21403  TTrack::TTrackMap SelectTrackMap; //build map so can find TrackElement at required H & V to build PrefDirElement from it //added at v2.9.0
21404  THVPair SelectTrackMapKeyPair; //for above
21405  TTrack::TTrackMapEntry SelectTrackMapEntry; //for above
21406  while(true) // recover active & inactive track (active first & top to bottom at leftmost position then again stepping right
21407  {
21408  wss.getline(LineString, 100);
21409  if(AnsiString(LineString) == "$$$") // end of track element marker
21410  {
21411  MarkerCounter++;
21412  break;
21413  }
21414  // if not $$$ then it's the SpeedTag number
21415  TTrackElement TE = Track->BuildBasicElementFromSpeedTag(5, AnsiString(LineString).ToInt());
21416  wss.getline(LineString, 100);
21417  TE.ActiveTrackElementName = AnsiString(LineString); // if not "$$$" must be the start of the next element
21418  wss.getline(LineString, 100);
21419  TE.ElementID = AnsiString(LineString);
21420  wss.getline(LineString, 100);
21421  TE.LocationName = AnsiString(LineString);
21422 
21423  wss.getline(LineString, 100);
21424  TE.CallingOnSet = AnsiString(LineString).ToInt();
21425  wss.getline(LineString, 100);
21426  TE.LCPlotted = AnsiString(LineString).ToInt();
21427  wss.getline(LineString, 100);
21428  TE.TempTrackMarker01 = AnsiString(LineString).ToInt();
21429  wss.getline(LineString, 100);
21430  TE.TempTrackMarker23 = AnsiString(LineString).ToInt();
21431 
21432  wss.getline(LineString, 100);
21433  TE.Attribute = AnsiString(LineString).ToInt();
21434  wss.getline(LineString, 100);
21435  TE.Conn[0] = AnsiString(LineString).ToInt();
21436  wss.getline(LineString, 100);
21437  TE.Conn[1] = AnsiString(LineString).ToInt();
21438  wss.getline(LineString, 100);
21439  TE.Conn[2] = AnsiString(LineString).ToInt();
21440  wss.getline(LineString, 100);
21441  TE.Conn[3] = AnsiString(LineString).ToInt();
21442  wss.getline(LineString, 100);
21443  TE.ConnLinkPos[0] = AnsiString(LineString).ToInt();
21444  wss.getline(LineString, 100);
21445  TE.ConnLinkPos[1] = AnsiString(LineString).ToInt();
21446  wss.getline(LineString, 100);
21447  TE.ConnLinkPos[2] = AnsiString(LineString).ToInt();
21448  wss.getline(LineString, 100);
21449  TE.ConnLinkPos[3] = AnsiString(LineString).ToInt();
21450  wss.getline(LineString, 100);
21451  TE.HLoc = AnsiString(LineString).ToInt();
21452  wss.getline(LineString, 100);
21453  TE.VLoc = AnsiString(LineString).ToInt();
21454  wss.getline(LineString, 100);
21455  TE.Length01 = AnsiString(LineString).ToInt();
21456  wss.getline(LineString, 100);
21457  TE.Length23 = AnsiString(LineString).ToInt();
21458  wss.getline(LineString, 100);
21459  TE.SpeedLimit01 = AnsiString(LineString).ToInt();
21460  wss.getline(LineString, 100);
21461  TE.SpeedLimit23 = AnsiString(LineString).ToInt();
21462  wss.getline(LineString, 100);
21463  TE.StationEntryStopLinkPos1 = AnsiString(LineString).ToInt();
21464  wss.getline(LineString, 100);
21465  TE.StationEntryStopLinkPos2 = AnsiString(LineString).ToInt();
21466  wss.getline(LineString, 100);
21467  TE.TrainIDOnElement = AnsiString(LineString).ToInt();
21468  wss.getline(LineString, 100);
21469  TE.TrainIDOnBridgeTrackPos01 = AnsiString(LineString).ToInt();
21470  wss.getline(LineString, 100);
21471  TE.TrainIDOnBridgeTrackPos23 = AnsiString(LineString).ToInt();
21472 
21473  wss.getline(LineString, 100);
21474  int temp = AnsiString(LineString).ToInt();
21475  if(temp == 0)
21476  {
21478  }
21479  else if(temp == 1)
21480  {
21482  }
21483  else if(temp == 2)
21484  {
21486  }
21487  else if(temp == 3)
21488  {
21490  }
21491  Track->SelectVector.push_back(TE);
21492  if((TE.TrackType != Concourse) && (TE.TrackType != Parapet) && (TE.TrackType != NamedNonStationLocation) && (TE.TrackType != Platform)
21493  && (TE.TrackType != LevelCrossing)) //aded at v2.9.2 so only active elements added to SelectTrackMap
21494  {
21495  SelectTrackMapKeyPair.first = TE.HLoc;
21496  SelectTrackMapKeyPair.second = TE.VLoc;
21497  SelectTrackMapEntry.first = SelectTrackMapKeyPair;
21498  SelectTrackMapEntry.second = Track->SelectVector.size() - 1;
21499  SelectTrackMap.insert(SelectTrackMapEntry);
21500  }
21501  }
21502 
21503  TextHandler->SelectTextVector.clear();
21504  AnsiString FontName;
21505  int FontSize, FontColour, FontCharset, FontStyle;
21506  while(true) // recover text
21507  {
21508  wss.getline(LineString, 1000);
21509  if(AnsiString(LineString) == "$$$") // end of text marker
21510  {
21511  MarkerCounter++;
21512  break;
21513  }
21514  // if not $$$ then it's the text string
21515  TTextItem TI;
21516  TI.TextString = AnsiString(LineString);
21517  wss.getline(LineString, 1000); //extended to 1000 from 100 for text items at v2.9.2
21518  TI.HPos = AnsiString(LineString).ToInt();
21519  wss.getline(LineString, 1000);
21520  TI.VPos = AnsiString(LineString).ToInt();
21521  wss.getline(LineString, 1000);
21522  FontName = AnsiString(LineString).c_str();
21523  wss.getline(LineString, 1000);
21524  FontSize = AnsiString(LineString).ToInt();
21525  wss.getline(LineString, 1000);
21526  FontColour = AnsiString(LineString).ToInt();
21527  wss.getline(LineString, 1000);
21528  FontCharset = AnsiString(LineString).ToInt();
21529  wss.getline(LineString, 1000);
21530  FontStyle = AnsiString(LineString).ToInt();
21531  // create a new font
21532  TFont *NewFont = new TFont;
21533  NewFont->Name = FontName;
21534  NewFont->Size = FontSize;
21535  NewFont->Color = static_cast<TColor>(FontColour);
21536  NewFont->Charset = FontCharset;
21537  NewFont->Style = TextHandler->SetFontStyleFromInt(1, FontStyle);
21538  TI.Font = NewFont;
21539  TextHandler->SelectTextVector.push_back(TI);
21540  }
21541 
21542  // recover select dimensions
21543  wss.getline(LineString, 100);
21544  SelectBitmap->Height = AnsiString(LineString).ToInt();
21545  wss.getline(LineString, 100);
21546  SelectBitmap->Width = AnsiString(LineString).ToInt();
21547  wss.getline(LineString, 100);
21548  SelectRect.left = AnsiString(LineString).ToInt();
21549  wss.getline(LineString, 100);
21550  SelectRect.top = AnsiString(LineString).ToInt();
21551  wss.getline(LineString, 100);
21552  if(AnsiString(LineString) == "$$$")
21553  {
21554  MarkerCounter++;
21555  }
21556 
21557  // recover pref dirs - after dimensions so that a clipboard loaded with this app will paste into an earlier version app without pref dirs
21558  // if a clipboard loaded with an earlier app is pasted into this app then the marker will be wrong, an error message will be given but no crash
21559  int TempTVPos, TempHLoc, TempVLoc, TempELink, TempELinkPos, TempXLink, TempXLinkPos, TempEXNumber, ATVecPos;
21560  bool FoundFlag;
21562  while(true)
21563  {
21564  wss.getline(LineString, 100);
21565  if(AnsiString(LineString) == "$$$") // end of pref dir element marker
21566  {
21567  MarkerCounter++;
21568  break;
21569  }
21570  // if not $$$ then it's the TVPos value
21571  TempTVPos = AnsiString(LineString).ToInt(); //added at v2.9.2 so all 9 CheckCount properties valid (SpeedTag loaded from corresponding TrackElement)
21572  wss.getline(LineString, 100);
21573  TempHLoc = AnsiString(LineString).ToInt();
21574  wss.getline(LineString, 100);
21575  TempVLoc = AnsiString(LineString).ToInt();
21576  wss.getline(LineString, 100);
21577  TempELink = AnsiString(LineString).ToInt();
21578  wss.getline(LineString, 100);
21579  TempELinkPos = AnsiString(LineString).ToInt();
21580  wss.getline(LineString, 100);
21581  TempXLink = AnsiString(LineString).ToInt();
21582  wss.getline(LineString, 100);
21583  TempXLinkPos = AnsiString(LineString).ToInt();
21584  wss.getline(LineString, 100);
21585  TempEXNumber = AnsiString(LineString).ToInt();
21586  //build a pref dir element from these values and the corresponding TrackVectorPosition for HLoc & VLoc
21587  TTrackElement TempElement = Track->GetTrackElementFromAnyTrackMap(0, TempHLoc, TempVLoc, SelectTrackMap, Track->SelectVector);
21588  TPrefDirElement TempPrefDirElement(TempElement);
21589 // TempPrefDirElement.HLoc = TempHLoc; //these and SpeedTag already set from TempElement
21590 // TempPrefDirElement.VLoc = TempVLoc;
21591  TempPrefDirElement.SetTrackVectorPosition(TempTVPos); //added at v2.9.2 so all 9 CheckCount properties have values (SpeedTag loaded from corresponding TrackElement)
21592  //TVPos only included for completeness & not valid yet, it will change to the correct value when pasted
21593  //and change again when the track is linked
21594  TempPrefDirElement.SetELink(TempELink);
21595  TempPrefDirElement.SetELinkPos(TempELinkPos);
21596  TempPrefDirElement.SetXLink(TempXLink);
21597  TempPrefDirElement.SetXLinkPos(TempXLinkPos);
21598  TempPrefDirElement.SetEXNumber(TempEXNumber);
21599  TempPrefDirElement.SetCheckCount(9); //added at v2.9.2
21600  SelectPrefDir->ExternalStorePrefDirElement(11, TempPrefDirElement); //added 27/05 at v2.9.0
21601  }
21602 
21603  if(MarkerCounter == 4)
21604  {
21605  ValidResult = true;
21606  }
21607  Utilities->CallLogPop(2269);
21608  }
21609 
21610  catch(const EClipboardException &e) //don't stop for any error in this section, just log it //non-error catch
21611  {
21612  ValidResult = false;
21613  TrainController->LogEvent("EClipboardException in RecoverClipboard - message = " + e.Message);
21614  Utilities->CallLogPop(2313);
21615  }
21616  catch(const Exception &e) //non-error catch - non-clipboard exception
21617  {
21618  ValidResult = false;
21619  TrainController->LogEvent("non-clipboard exception in RecoverClipboard - message = " + e.Message);
21620  Utilities->CallLogPop(2322);
21621  }
21622 
21623 }
21624 
21625 // ---------------------------------------------------------------------------
21626 
21627 /*
21628  Problems with ifstream reading (see 'SessionFileIntegrityCheck(AnsiString FileName)' above):-
21629 
21630  These problems were with Borland C++Builder 4.
21631 
21632  The functions saved in OldFiles\Backups220809Duringifstream testing were used for testing the odd behaviour where the
21633  ifstream pointer gave different characters using get() and getline(), when reading the timetable entries in the session
21634  file for 20/08/09 at 18:45 (saved). All was well until point 48677 in the session file, when for some reason the
21635  getline(0 & get(0 gave different results. Many earlier timetable strings had been read OK before that, and it wasn't
21636  clear what was special about this particular string.
21637  Later more detailed study found that on reading the string beginning at point 48605 (i.e. the one earlier than above),
21638  within function CheckNoNewLineAtStartNonZeroTerminatedFileString the file pointer (using tellg()) reduced from 48606 to
21639  48604 after reading the 'F' character. Thereafter characters were read correctly but the pointer remained 2 too low.
21640  This is thought to be a flaw in the compiler.
21641  Later again additional tellg()s and a seekg()s were included in CheckNoNewLineAtStartNonZeroTerminatedFileString, and
21642  though these should have had no effect they somehow caused the next getline() within CheckTimetableFromSessionFile to
21643  read a null, even though the pointer had been reset to its value before the call to
21644  CheckNoNewLineAtStartNonZeroTerminatedFileString. Again this seems to be a flaw in the compiler, where the pointer
21645  that is indicated by tellg and the true pointer within the system can be different.
21646  Tried the old c++ stream library to see if that worked but it was exactly the same. Probably because the same code is
21647  used for both with the new library just defined within the std namespace.
21648  Success!! Traced to the putback function failing. It (apparently) can't be used if the file pointer has been altered
21649  after the last read that is to be put back. Corrected that & the most recent session file checked out & loaded OK.
21650  (note - don't need the ifstream file to be open in output mode for the putback to work)
21651  But: the earlier file - 18:45 as above - still fails to advance the file pointer in the middle of checking the
21652  timetable, it sticks at position 48601. This position points to 'r' in 'Frh' just before a newline. Also the file
21653  integrity is OK up to and after this sticking point. Oddly though the loading function works fine (i.e. by bypassing
21654  the integrity check function), though the timetable isn't read directly, it is copied to a new stand-alone timetable
21655  file and that read by the program.
21656  Created a new version of CheckNoNewLineAtStartNonZeroTerminatedFileString with 'New' at end, & got rid of all the
21657  internal digressions & getlines. This passed the earlier sticking point, but stuck later at 48677, i.e. the 'h' from
21658  'Frh' at the end of the entry following that for the earlier sticking point. Here
21659  CheckNoNewLineAtStartNonZeroTerminatedFileStringNew works fine, with end pointer correctly set at 48680, i.e. after the
21660  newline, but the subsequent getline() function, although it retrieves the line correctly, the file pointer is set to
21661  48677, i.e. before the newline, so getline seems to fail to extract the newline character. Still to check - why doesn't
21662  CheckNoNewLineAtStartNonZeroTerminatedFileStringNew see 'h' instead of '0' in the subsequent read? If it did the two
21663  would tally, though would still be wrong.
21664  Further investigation:- CheckNoNewLineAtStartNonZeroTerminatedFileStringNew doesn't seem to recognize the file pointer
21665  as set by seekg at 48677. It continues to read at the point it left off earlier, whereas getline() does read at 48677
21666  & recovers 'h'. Continuing to apply getline() after the above effect it is found that it doesn't extract newlines after
21667  reading further lines, but extracts them when read alone i.e. it reads a line then a null in succession, although the
21668  lines are only separated by single newline characters.
21669 
21670  Need to check:
21671  1. Does the file read correctly if only get() functions used without getline() and without resetting the file pointer?
21672  2. Does the file read correctly if only getline() functions used without get() and without resetting the file pointer?
21673  3. Does the file read correctly if get() functions alternated with getline() but without resetting the file pointer?
21674 
21675  For 1: Still goes wrong at usual place, reads 'h' at the same point. Try not resetting the file pointer with seekg.
21676  Tried this - got past the earlier point but failed later with a reduction in file pointer after a character read. In
21677  fact the reduction was by 40 bytes for reading a single comma! Try without any tellg's - yes, that got past all the
21678  timetable OK. So, works OK with just get() providing no tellg's (& no seekg's).
21679 
21680  For 2: Works OK using getline().
21681 
21682  For 3: Gets to end of timetable OK but the next tellg gives a wrong value. Check if using getline() alone gives a
21683  wrong tellg. Tried getline() alone, reached end of TT as before, but gave the same wrong file pos on using tellg.
21684  Try continuing to see if works OK in spite of tellg giving wrong result. Yes it works OK. Hence the problem seems to
21685  be tellg, which sometimes returns wrong results, and they corrupt things when used in seekg.
21686 
21687  Overall conclusion: Avoid all tellg's & seekg's. If need to reset a file position then close and reopen it.
21688 */
21689 
21690 // ---------------------------------------------------------------------------
21691 
21692 
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17550
TInterface::CopyTTEntryButtonClick
void __fastcall CopyTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3868
TInterface::CtrlKey
bool CtrlKey
true when the CTRL key is pressed (see also ShiftKey)
Definition: InterfaceUnit.h:968
TInterface::MTBFEditBox
TEdit * MTBFEditBox
Definition: InterfaceUnit.h:489
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:11321
TInterface::ScreenLeftButtonClick
void __fastcall ScreenLeftButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9072
TInterface::ExitMenuItem
TMenuItem * ExitMenuItem
Definition: InterfaceUnit.h:425
TTrain::AllowedToPassRedSignal
bool AllowedToPassRedSignal
set when train has been called on, or when under signaller control and instructed to pass a red signa...
Definition: TrainUnit.h:349
TInterface::TextMoveVPos
int TextMoveVPos
used to store the original text 'H' & 'V' positions for use during text moving
Definition: InterfaceUnit.h:1149
TInterface::OperMode
@ OperMode
Definition: InterfaceUnit.h:871
TInterface::CPDirectionsCheckBox
TCheckBox * CPDirectionsCheckBox
Definition: InterfaceUnit.h:668
TTrain::ZeroPowerNoNewShuttleFromNonRepeatMessage
bool ZeroPowerNoNewShuttleFromNonRepeatMessage
Definition: TrainUnit.h:316
TTrain::ZeroPowerNoNewServiceMessage
bool ZeroPowerNoNewServiceMessage
Definition: TrainUnit.h:315
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TPrefDirElement::SetEXGraphicPtr
void SetEXGraphicPtr(Graphics::TBitmap *input)
Used in pasting pref dirs.
Definition: TrackUnit.h:382
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:11294
TInterface::AddPrefDirButton
TBitBtn * AddPrefDirButton
Definition: InterfaceUnit.h:122
TInterface::RemoveTrainMenuItem
TMenuItem * RemoveTrainMenuItem
Definition: InterfaceUnit.h:476
TInterface::LocationNamesSetImage
TImage * LocationNamesSetImage
Definition: InterfaceUnit.h:286
TInterface::SpeedLimitBox
TEdit * SpeedLimitBox
distance/speed setting edit box that accepts speed limits
Definition: InterfaceUnit.h:98
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TInterface::SaveImageAndGridMenuItemClick
void __fastcall SaveImageAndGridMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2821
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:80
TTrainController
Handles all train and timetable activities, only one object created.
Definition: TrainUnit.h:648
TInterface::FloatingInfoMenu
TMenuItem * FloatingInfoMenu
Definition: InterfaceUnit.h:452
TInterface::NewTTEntryKeyFlag
bool NewTTEntryKeyFlag
Definition: InterfaceUnit.h:1071
TInterface::ConflictAnalysisButtonClick
void __fastcall ConflictAnalysisButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14026
TInterface::CallingOnButton
TSpeedButton * CallingOnButton
Definition: InterfaceUnit.h:211
TInterface::BuildTrainDataVectorForValidateFile
bool BuildTrainDataVectorForValidateFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway)
Check the integrity of a stored timetable file (either as a stand alone file or within a session file...
Definition: InterfaceUnit.cpp:19305
TInterface::SelectBitmapMouseLocX
int SelectBitmapMouseLocX
when flag SelectPickedUp is set to true (see above - to allow a selected screen area to move during M...
Definition: InterfaceUnit.h:1125
TInterface::PrefDirPanel
TPanel * PrefDirPanel
'Set preferred directions' panel
Definition: InterfaceUnit.h:367
TInterface::PrefDirPanelLabel
TLabel * PrefDirPanelLabel
label to the left of PrefDirPanel
Definition: InterfaceUnit.h:313
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:12840
TInterface::MTBFEditBoxKeyUp
void __fastcall MTBFEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:13816
TInterface::TrackMode
@ TrackMode
Definition: InterfaceUnit.h:871
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1702
TInterface::SaveSessionButton
TBitBtn * SaveSessionButton
Definition: InterfaceUnit.h:207
TInterface::TTClockx1ButtonClick
void __fastcall TTClockx1ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13397
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:190
TInterface::LengthConversionPanel
TPanel * LengthConversionPanel
Definition: InterfaceUnit.h:111
TInterface::ChangeDirectionMenuItem
TMenuItem * ChangeDirectionMenuItem
Definition: InterfaceUnit.h:471
TTrain::MidEntryPos
int MidEntryPos
Definition: TrainUnit.h:337
TTrainController::RebuildOpTimeToActMultimap
void RebuildOpTimeToActMultimap(int Caller)
new v2.2.0 for OperatorActionPanel
Definition: TrainUnit.cpp:19357
TTrainController::PwrHigh
bool PwrHigh
Definition: TrainUnit.h:756
TInterface::StepForwardMenuItem
TMenuItem * StepForwardMenuItem
Definition: InterfaceUnit.h:474
TTrack::SelectGraphicVector
TUserGraphicVector SelectGraphicVector
Definition: TrackUnit.h:810
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:93
SignallerMoveForwards
@ SignallerMoveForwards
Definition: TrainUnit.h:51
TInterface::SignallerControlStopMenuItem
TMenuItem * SignallerControlStopMenuItem
Definition: InterfaceUnit.h:475
TRailGraphics::ConvertSignalsToOppositeHand
void ConvertSignalsToOppositeHand(int Caller)
Converts all signal graphics to opposite hand new at v2.3.0.
Definition: GraphicUnit.cpp:4359
TInterface::SpeedButton70
TSpeedButton * SpeedButton70
Definition: InterfaceUnit.h:582
TInterface::FormResize
void __fastcall FormResize(TObject *Sender)
Definition: InterfaceUnit.cpp:13669
TInterface::SaveTTAsButtonClick
void __fastcall SaveTTAsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4338
TInterface::SelectBitmapHLoc
int SelectBitmapHLoc
the original (prior to moving & after finished moving) HLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1123
TInterface::OperatorActionButton
TBitBtn * OperatorActionButton
Definition: InterfaceUnit.h:208
TInterface::DistanceKey
TImage * DistanceKey
information panel displayed when setting distances & speed limits
Definition: InterfaceUnit.h:276
AboutUnit.h
Arrive
@ Arrive
Definition: TrainUnit.h:50
TInterface::OperatorActionPanelDragStartX
int OperatorActionPanelDragStartX
mouse 'X' position when the OperatorActionPanel begins to be dragged
Definition: InterfaceUnit.h:1111
TInterface::PasteWarningSentFlag
bool PasteWarningSentFlag
indicates that the warning message about pasting overwriting the area has been given,...
Definition: InterfaceUnit.h:998
TInterface::StartWholeRailwayMoveVPos
int StartWholeRailwayMoveVPos
mouse Y position when start to move the whole railway
Definition: InterfaceUnit.h:1135
TTrain::ZeroPowerNoCDTMessage
bool ZeroPowerNoCDTMessage
Definition: TrainUnit.h:314
TTrain::CallingOnFlag
bool CallingOnFlag
calling on permitted
Definition: TrainUnit.h:355
TInterface::UnrestrictedButton
TBitBtn * UnrestrictedButton
Definition: InterfaceUnit.h:203
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:811
TRailGraphics::SpeedBut72NormBlackGlyph
Graphics::TBitmap * SpeedBut72NormBlackGlyph
Definition: GraphicUnit.h:1050
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:12880
TInterface::ExportTTMenuItemClick
void __fastcall ExportTTMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3232
TInterface::RestoreTTKeyFlag
bool RestoreTTKeyFlag
Definition: InterfaceUnit.h:1077
TInterface::CancelSelectionMenuItemClick
void __fastcall CancelSelectionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10770
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3625
TInterface::PERFLOG_DIR_NAME
static const UnicodeString PERFLOG_DIR_NAME
Definition: InterfaceUnit.h:884
TInterface::WholeRailwayMoving
bool WholeRailwayMoving
true when moving the railway with the mouse, new at v2.1.0
Definition: InterfaceUnit.h:1056
TInterface::TextFoundFlag
bool TextFoundFlag
indicates that a text item has been found when clicking on a build screen during 'AddText' or 'MoveTe...
Definition: InterfaceUnit.h:1030
TInterface::DisableRouteButtons
void DisableRouteButtons(int Caller)
Called during operation whenever the route type buttons need to be disabled, e.g. when paused.
Definition: InterfaceUnit.cpp:20141
TInterface::OperateRailwayMenuItemClick
void __fastcall OperateRailwayMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2149
TInterface::DerailImage
TImage * DerailImage
Definition: InterfaceUnit.h:272
TTrain::MaxRunningSpeed
double MaxRunningSpeed
the current maximum train running speed
Definition: TrainUnit.h:395
TRailGraphics::smLC
Graphics::TBitmap * smLC
Definition: GraphicUnit.h:881
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:794
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:299
TRailGraphics::SpeedBut75NormBlackGlyph
Graphics::TBitmap * SpeedBut75NormBlackGlyph
Definition: GraphicUnit.h:1053
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7137
RestoreTimetableControl
@ RestoreTimetableControl
Definition: TrainUnit.h:51
TTrainController::LastSessionSaveTTClockTime
TDateTime LastSessionSaveTTClockTime
Definition: TrainUnit.h:659
TInterface::TTSelectedEntry
AnsiString TTSelectedEntry
used to record the current timetable entry when changing to AZ order or back to original order
Definition: InterfaceUnit.h:949
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:48
TAllRoutes::AutoSigsRoute
@ AutoSigsRoute
Definition: TrackUnit.h:1631
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5609
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:7038
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5636
TActionVectorEntry::LocationType
TTimetableLocationType LocationType
indicates where the train is when the relevant action occurs
Definition: TrainUnit.h:121
TInterface::MasterClockTimer
void __fastcall MasterClockTimer(TObject *Sender)
Definition: InterfaceUnit.cpp:8327
TTrack::GapFlashGreenPosition
int GapFlashGreenPosition
Definition: TrackUnit.h:778
TInterface::MainScreen
TImage * MainScreen
the railway display screen
Definition: InterfaceUnit.h:293
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:68
TInterface::CutMenuItem
TMenuItem * CutMenuItem
Definition: InterfaceUnit.h:440
TInterface::LCResetCounter
unsigned int LCResetCounter
count up to 20 then resets - to check LCs & raise barriers if no route & no train present
Definition: InterfaceUnit.h:1097
TInterface::BlueBgndMenuItem
TMenuItem * BlueBgndMenuItem
Definition: InterfaceUnit.h:435
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1908
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:10216
TInterface::ResetChangedFileDataAndCaption
void ResetChangedFileDataAndCaption(int Caller, bool NonPrefDirChangesMade)
Called whenever the railway is changed to deal with title displays (loaded railway and timetable) and...
Definition: InterfaceUnit.cpp:18062
TInterface::ClpBrdValid
AnsiString ClpBrdValid
set to RlyClpBrdCopy or RlyClpBrd_Cut when Windows Clipboard contains a valid railway segment
Definition: InterfaceUnit.h:925
TTrain::MaxBrakeRate
double MaxBrakeRate
the maximum brake rate that the train can achieve
Definition: TrainUnit.h:399
session_api_
API * session_api_
Definition: InterfaceUnit2.10.0.cpp:70
TInterface::IMAGE_DIR_NAME
static const UnicodeString IMAGE_DIR_NAME
Definition: InterfaceUnit.h:886
TInterface::ShowPerformancePanel
bool ShowPerformancePanel
true when the 'show performance panel' button has been clicked during operation
Definition: InterfaceUnit.h:1024
TInterface::LoadSessionDialog
TOpenDialog * LoadSessionDialog
Definition: InterfaceUnit.h:497
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TInterface::OutputLog10MouseDown
void __fastcall OutputLog10MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12762
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:625
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2804
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5789
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:152
TTrain::MidExitPos
int MidExitPos
Definition: TrainUnit.h:337
TInterface::NewSelectBitmapVLoc
int NewSelectBitmapVLoc
as above for VLoc
Definition: InterfaceUnit.h:1109
TInterface::MoveTextOrGraphic
@ MoveTextOrGraphic
Definition: InterfaceUnit.h:903
TInterface::ScreenGridButton
TBitBtn * ScreenGridButton
Definition: InterfaceUnit.h:78
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:8056
TInterface::EditMenu
TMenuItem * EditMenu
Definition: InterfaceUnit.h:437
TTrain::TrainFailed
bool TrainFailed
added at v2.4.0 to indicate failure
Definition: TrainUnit.h:381
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:435
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:663
DisplayUnit.h
TInterface::ResetSelectRect
void ResetSelectRect()
SelectRect is the rectangle selected via the 'Edit'menu, and this function sets left,...
Definition: InterfaceUnit.cpp:20876
TInterface::TTClockAdjustWarningHide
bool TTClockAdjustWarningHide
true if user opts not to show the timetable clock adjustment warning (false on starting the program)
Definition: InterfaceUnit.h:1032
TTrain::ZeroPowerNoFrontSplitMessage
bool ZeroPowerNoFrontSplitMessage
Definition: TrainUnit.h:310
TTrainController::SPADWarning
bool SPADWarning
Definition: TrainUnit.h:742
TInterface::TTClockAdjustCheckBox
TCheckBox * TTClockAdjustCheckBox
Definition: InterfaceUnit.h:235
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:12619
TInterface::TrackNotLinkedImage
TImage * TrackNotLinkedImage
Definition: InterfaceUnit.h:283
TTrain::DepartureTimeSet
bool DepartureTimeSet
set when stopped at a location and the next action is departure (set in UpdateTrain when ReleaseTime ...
Definition: TrainUnit.h:357
TInterface::WarningHover
bool WarningHover
true when mouse hovers over warning messages during operation - to prevent clicking while changing
Definition: InterfaceUnit.h:1054
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7523
TInterface::SaveTTAsButton
TButton * SaveTTAsButton
Definition: InterfaceUnit.h:152
TInterface::ZoomButtonClick
void __fastcall ZoomButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9317
TTrain::LagElement
int LagElement
Definition: TrainUnit.h:337
TTrack::GetLocationName
AnsiString GetLocationName(unsigned int InactiveTrackVectorPosition)
Return location name for a given inactive track vector position.
Definition: TrackUnit.h:825
TTrainController::BufferAttentionWarning
bool BufferAttentionWarning
Definition: TrainUnit.h:742
TInterface::ExitTrackButtonClick
void __fastcall ExitTrackButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1833
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:9441
TInterface::RouteCancelFlag
bool RouteCancelFlag
true when route cancel button pressed, enables a right mouse click to cancel a route if in an appropr...
Definition: InterfaceUnit.h:1010
TTextHandler::LoadText
void LoadText(int Caller, std::ifstream &VecFile)
load the railway's text from VecFile
Definition: TextUnit.cpp:297
TInterface::SpeedToggleButton2Click
void __fastcall SpeedToggleButton2Click(TObject *Sender)
Definition: InterfaceUnit.cpp:12915
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:13909
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:14961
TInterface::LoadNormalSignalGlyphs
void LoadNormalSignalGlyphs(int Caller)
In trackbuild display normal signal types on signal buttons.
Definition: InterfaceUnit.cpp:21024
TInterface::MainScreenMouseDown3
void MainScreenMouseDown3(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
Called when mouse button clicked in zoom-out mode.
Definition: InterfaceUnit.cpp:7510
TInterface::CancelTTEntryButton
TButton * CancelTTEntryButton
Definition: InterfaceUnit.h:143
TInterface::UserGraphicVectorNumber
int UserGraphicVectorNumber
used to store a single item of user graphics
Definition: InterfaceUnit.h:1151
TInterface::PreviousTTEntryButton
TButton * PreviousTTEntryButton
Definition: InterfaceUnit.h:134
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:17510
TInterface::TrackElementPanel
TPanel * TrackElementPanel
panel containing the track/location/parapet element buttons
Definition: InterfaceUnit.h:384
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:18346
TInterface::SelectionValid
bool SelectionValid
true when an area of screen has been selected via the 'Edit' & 'Select' or 'Reselect' menu items
Definition: InterfaceUnit.h:1016
TDisplay::InvertElement
void InvertElement(int Caller, int HPos, int VPos)
Definition: DisplayUnit.cpp:142
TTrack::NoPlatsMessageSent
bool NoPlatsMessageSent
used to send no platforms warning once only
Definition: TrackUnit.h:757
TInterface::OperateButtonClick
void __fastcall OperateButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2168
TInterface::WhiteBgndMenuItem
TMenuItem * WhiteBgndMenuItem
Definition: InterfaceUnit.h:433
TInterface::ContinuationAutoSignals
void ContinuationAutoSignals(int Caller, TDateTime Now)
Deal with signal resetting on auto signal routes that extend to continuations where trains have depar...
Definition: InterfaceUnit.cpp:16237
TTrainController::CrashWarning
bool CrashWarning
Definition: TrainUnit.h:742
TInterface::LoadInterface
void LoadInterface(int Caller, std::ifstream &SessionFile)
Load the interface part of a session file.
Definition: InterfaceUnit.cpp:18568
TTrain::PlotTrain
void PlotTrain(int Caller, TDisplay *Disp)
Plots the train on the display in normal (zoomed-in) mode.
Definition: TrainUnit.cpp:8347
TInterface::AutoSigsFlag
bool AutoSigsFlag
true when AutoSig route building selected during operation
Definition: InterfaceUnit.h:956
TInterface::SetRouteButtonsInfoCaptionAndRouteNotStarted
void SetRouteButtonsInfoCaptionAndRouteNotStarted(int Caller)
Enables or disables the route type buttons depending on the route mode, sets the information panel me...
Definition: InterfaceUnit.cpp:20014
TInterface::MoveForwardsMenuItem
TMenuItem * MoveForwardsMenuItem
Definition: InterfaceUnit.h:472
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:159
TInterface::YardEdit
TEdit * YardEdit
Definition: InterfaceUnit.h:106
TInterface::SigPrefConsecButtonClick
void __fastcall SigPrefConsecButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2233
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3642
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4431
TInterface::Paused
@ Paused
Definition: InterfaceUnit.h:893
TTrainController::SaveSessionTrains
void SaveSessionTrains(int Caller, std::ofstream &SessionFile)
save trains to a session file
Definition: TrainUnit.cpp:14976
TInterface::TrackInfoMenuItem
TMenuItem * TrackInfoMenuItem
Definition: InterfaceUnit.h:453
TRailGraphics::SpeedBut73NormBlackGlyph
Graphics::TBitmap * SpeedBut73NormBlackGlyph
Definition: GraphicUnit.h:1051
TInterface::Operating
@ Operating
Definition: InterfaceUnit.h:893
TTextHandler
A single object that handles text management.
Definition: TextUnit.h:62
TInterface::EditTimetableMenuItemClick
void __fastcall EditTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3390
TInterface::TakeSignallerControlMenuItemClick
void __fastcall TakeSignallerControlMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11293
TInterface::TimetableMode
@ TimetableMode
Definition: InterfaceUnit.h:871
TInterface::ScreenUpButtonClick
void __fastcall ScreenUpButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9256
TInterface::ShowHideTTButtonClick
void __fastcall ShowHideTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3568
TInterface::ImageMenu
TMenuItem * ImageMenu
Definition: InterfaceUnit.h:459
TInterface::LoadGroundSignalGlyphs
void LoadGroundSignalGlyphs(int Caller)
In trackbuild display ground signal types on signal buttons.
Definition: InterfaceUnit.cpp:21040
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:172
TInterface::CPArrivalsCheckBox
TCheckBox * CPArrivalsCheckBox
Definition: InterfaceUnit.h:248
TInterface::OneEntryTimetableMemo
TMemo * OneEntryTimetableMemo
the single service editing and display area on the right hand side of the timetable edit screen
Definition: InterfaceUnit.h:405
TInterface::SelectBitmapVLoc
int SelectBitmapVLoc
the original (prior to moving & after finished moving) VLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1129
TInterface::LengthOKButtonClick
void __fastcall LengthOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1461
TInterface::OutputLog1MouseDown
void __fastcall OutputLog1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12674
NotStarted
@ NotStarted
Definition: TrainUnit.h:86
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4591
TInterface::AppDeactivate
void __fastcall AppDeactivate(TObject *Sender)
Definition: InterfaceUnit.cpp:821
TInterface::UnrestrictedButtonClick
void __fastcall UnrestrictedButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2312
TInterface::ExportTTMenuItem
TMenuItem * ExportTTMenuItem
Definition: InterfaceUnit.h:423
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6321
TInterface::SaveTTKeyFlag
bool SaveTTKeyFlag
Definition: InterfaceUnit.h:1075
TRailGraphics::SpeedBut71NormBlackGlyph
Graphics::TBitmap * SpeedBut71NormBlackGlyph
Definition: GraphicUnit.h:1049
TInterface::SelectNewGraphicClick
void __fastcall SelectNewGraphicClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13964
TInterface::SpeedButtonClick
void __fastcall SpeedButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:948
TTrack::GetHLocMax
int GetHLocMax()
Definition: TrackUnit.h:876
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3518
TInterface::CPEditArrRange
TEdit * CPEditArrRange
Definition: InterfaceUnit.h:251
TInterface::ErrorButtonClick
void __fastcall ErrorButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12057
TTrainController::SPADEvents
int SPADEvents
Definition: TrainUnit.h:794
TInterface::PasteTTEntryButton
TButton * PasteTTEntryButton
Definition: InterfaceUnit.h:138
TTrain::ZeroPowerNoRepeatShuttleMessage
bool ZeroPowerNoRepeatShuttleMessage
Definition: TrainUnit.h:317
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1309
TInterface::SetLevel2PrefDirMode
void SetLevel2PrefDirMode(int Caller)
Sets the Level2PrefDirMode user mode, using the Level2PrefDirMode variable to determine the mode.
Definition: InterfaceUnit.cpp:15917
TInterface::SetGapsButton
TBitBtn * SetGapsButton
Definition: InterfaceUnit.h:70
TTrain::ActionVectorEntryPtr
TActionVectorEntry * ActionVectorEntryPtr
points to the current position in the ActionVector (a member of the TTrainDataEntry class)
Definition: TrainUnit.h:345
TTrainDataEntry
Contains all data for a single timetable service entry.
Definition: TrainUnit.h:186
TPrefDirElement::SetXLinkPos
void SetXLinkPos(int input)
Used in pasting pref dirs.
Definition: TrackUnit.h:370
clSignalStopBackground
#define clSignalStopBackground
Definition: GraphicUnit.h:299
TTrainController::LateDeps
int LateDeps
Definition: TrainUnit.h:785
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:18820
TInterface::ExitMenuItemClick
void __fastcall ExitMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5720
TrackUnit.h
TInterface::ScreenDownButtonClick
void __fastcall ScreenDownButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9194
TInterface::api_oper_mode_
int api_oper_mode_
Definition: InterfaceUnit.h:920
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:19015
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9427
TDisplay::ClearDisplay
void ClearDisplay(int Caller)
Empty the display.
Definition: DisplayUnit.cpp:183
TDisplay::Top
int Top()
Return the top pixel position of the screen.
Definition: DisplayUnit.h:120
TInterface::ExitPrefDirButtonClick
void __fastcall ExitPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2130
TInterface::SaveErrorFile
void SaveErrorFile()
Save the error log after an error has been thrown - no need for a caller.
Definition: InterfaceUnit.cpp:20154
TTrain::SendMissedActionLogs
void SendMissedActionLogs(int Caller, int IncNum, TActionVectorEntry *Ptr)
Missed actions (see NameInTimetableBeforeCDT above) sent to the performance log and performance file.
Definition: TrainUnit.cpp:6298
TInterface::SpeedVariableLabel2
TLabel * SpeedVariableLabel2
Definition: InterfaceUnit.h:119
TInterface::TrainInfoMenuItem
TMenuItem * TrainInfoMenuItem
Definition: InterfaceUnit.h:455
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1524
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1610
TInterface::TrainStatusInfoOnOffMenuItemClick
void __fastcall TrainStatusInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5786
TInterface::ConverttoRightHandSignalsMenuItem
TMenuItem * ConverttoRightHandSignalsMenuItem
Definition: InterfaceUnit.h:477
TInterface::TTClockxHalfButtonClick
void __fastcall TTClockxHalfButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13416
TInterface::OutputLog3
TLabel * OutputLog3
Definition: InterfaceUnit.h:302
TTextHandler::GetFontStyleAsInt
int GetFontStyleAsInt(int Caller, TFont *InputFont)
retrieve the style of the font as a coded integer
Definition: TextUnit.cpp:99
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
TOnePrefDir::ExternalStorePrefDirElement
void ExternalStorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map - used by other classes.
Definition: TrackUnit.h:1439
clB5G5R4
#define clB5G5R4
Definition: GraphicUnit.h:285
Utilities.h
TInterface::SetTrackModeEditMenu
void SetTrackModeEditMenu(int Caller)
Enables or disables the initial Edit mode submenu items in Track mode.
Definition: InterfaceUnit.cpp:20743
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:678
TInterface::SaveImageNoGridMenuItemClick
void __fastcall SaveImageNoGridMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2729
TInterface::HelpMenu
TMenuItem * HelpMenu
Definition: InterfaceUnit.h:465
TInterface::TrackOKButtonClick
void __fastcall TrackOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1029
TTrainController::CheckSessionLockedRoutes
bool CheckSessionLockedRoutes(int Caller, std::ifstream &SessionFile)
Part of the session file integrity check for locked routes, true for success.
Definition: TrainUnit.cpp:15079
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3242
TInterface::GapsSetImage
TImage * GapsSetImage
Definition: InterfaceUnit.h:284
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:15495
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:221
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TInterface::LocationNameComboBoxKeyUp
void __fastcall LocationNameComboBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4911
TInterface::ClipboardChecked
bool ClipboardChecked
used to prevent Windows clipboard beng checked repeatedly
Definition: InterfaceUnit.h:960
TInterface::RevertToOriginalRouteSelector
void RevertToOriginalRouteSelector(int Caller)
Clears any route start markers, enables or disables the route cancel button, and resets the informati...
Definition: InterfaceUnit.cpp:14615
TInterface::FileIntegrityCheck
bool FileIntegrityCheck(int Caller, char *FileName) const
Check integrity of a railway file prior to loading, return true for success.
Definition: InterfaceUnit.cpp:14452
TInterface::TTLastServicePtr
TTEVPtr TTLastServicePtr
timetable entry value pointers used during timetable editing
Definition: InterfaceUnit.h:1192
TTrainController::CheckSessionTrains
bool CheckSessionTrains(int Caller, std::ifstream &InFile)
Part of the session file integrity check for train entries, true for success.
Definition: TrainUnit.cpp:15017
TakeSignallerControl
@ TakeSignallerControl
Definition: TrainUnit.h:50
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:12685
Simple
@ Simple
Definition: TrackUnit.h:67
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:798
TTrain::ZeroPowerNoRepeatShuttleOrNewServiceMessage
bool ZeroPowerNoRepeatShuttleOrNewServiceMessage
flags to indicate whether the respective message has been sent
Definition: TrainUnit.h:318
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:40
TInterface::DeleteMenuItem
TMenuItem * DeleteMenuItem
Definition: InterfaceUnit.h:446
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2853
TInterface::TTClockAdjustOKButtonClick
void __fastcall TTClockAdjustOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13981
TInterface::ChangeDirectionMenuItemClick
void __fastcall ChangeDirectionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11497
TInterface::PointsFlashDuration
float PointsFlashDuration
duration of the flash period when changing points manually
Definition: InterfaceUnit.h:1086
TInterface::LocationNameComboBoxClick
void __fastcall LocationNameComboBoxClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4840
TInterface::TTServiceSyntaxCheckKeyFlag
bool TTServiceSyntaxCheckKeyFlag
Definition: InterfaceUnit.h:1073
TInterface::TLevel2OperMode
TLevel2OperMode
Definition: InterfaceUnit.h:892
TInterface::ConsecSignalsRoute
bool ConsecSignalsRoute
true when AutoSig or preferred route building selected during operation (always same state as Preferr...
Definition: InterfaceUnit.h:962
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1377
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:12936
TTrack::WriteTrackAndTextToImage
void WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3835
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5749
TTrain::BackgroundColour
TColor BackgroundColour
the background colour of the train's headcode graphics
Definition: TrainUnit.h:465
TInterface::LengthCancelButtonClick
void __fastcall LengthCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1668
TInterface::OutputLog5
TLabel * OutputLog5
Definition: InterfaceUnit.h:304
TTrain
Definition: TrainUnit.h:281
TTrainController::CheckTimeValidity
bool CheckTimeValidity(int Caller, AnsiString TimeStr, TDateTime &Time)
returns true if the time complies with requirements
Definition: TrainUnit.cpp:10621
clSignallerStopped
#define clSignallerStopped
Definition: GraphicUnit.h:298
TTextHandler::SelectTextVector
TTextVector SelectTextVector
Definition: TextUnit.h:69
TTrackElement::TrainIDOnBridgeTrackPos23
int TrainIDOnBridgeTrackPos23
Set to the TrainID value when a train is present on the element, bridges can have two trains present ...
Definition: TrackUnit.h:154
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11335
TInterface::CallOnImage
TImage * CallOnImage
Definition: InterfaceUnit.h:269
TInterface::PerformancePanelDragStartY
int PerformancePanelDragStartY
as above for 'Y'
Definition: InterfaceUnit.h:1120
TInterface::LocationNameTextBox
TEdit * LocationNameTextBox
edit box that accepts location names
Definition: InterfaceUnit.h:100
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:644
TInterface::SaveSessionFlag
bool SaveSessionFlag
true when a session save command has been given - implemented at next clock tick
Definition: InterfaceUnit.h:1012
TTrainController::ContinuationTrainExpectationMultiMap
TContinuationTrainExpectationMultiMap ContinuationTrainExpectationMultiMap
Multimap for TContinuationTrainExpectationEntry objects, the access key is the expectation time.
Definition: TrainUnit.h:818
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7538
TInterface::SpeedButton73
TSpeedButton * SpeedButton73
Definition: InterfaceUnit.h:585
TTrain::StoppedForTrainInFront
bool StoppedForTrainInFront
Definition: TrainUnit.h:442
TInterface::ConflictAnalysisKeyFlag
bool ConflictAnalysisKeyFlag
Definition: InterfaceUnit.h:1079
GapJump
@ GapJump
Definition: TrackUnit.h:67
TInterface::Level2OperMode
enum TInterface::TLevel2OperMode Level2OperMode
TInterface::SigsOnRightImage1
TImage * SigsOnRightImage1
Definition: InterfaceUnit.h:290
TInterface::SaveRailwayPDPButton
TBitBtn * SaveRailwayPDPButton
Save button on PrefDirPanel.
Definition: InterfaceUnit.h:125
TTrainController::MissedStops
int MissedStops
Definition: TrainUnit.h:788
TInterface::TempTTFileName
AnsiString TempTTFileName
the name for the temporary file used to save loaded timetables for storage in session files & error l...
Definition: InterfaceUnit.h:947
TInterface::PrefDirMode
@ PrefDirMode
Definition: InterfaceUnit.h:871
TInterface::PassRedSignalMenuItem
TMenuItem * PassRedSignalMenuItem
Definition: InterfaceUnit.h:473
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7284
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:150
TRailGraphics::bmGreenRect
Graphics::TBitmap * bmGreenRect
Definition: GraphicUnit.h:521
TInterface::TTClockExitButtonClick
void __fastcall TTClockExitButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13276
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:150
TTrack::IsReadyForOperation
bool IsReadyForOperation(bool GiveMessage)
Indicates whether or not the railway is ready for saving as a '.rly' file and for operation.
Definition: TrackUnit.h:831
TTrack::Raising
@ Raising
Definition: TrackUnit.h:625
TInterface::OAListBoxRightMouseButtonDown
bool OAListBoxRightMouseButtonDown
flag set when right mouse button clicked over op action list box, so floating information window show...
Definition: InterfaceUnit.h:996
TTrainController::FinishedOperation
void FinishedOperation(int Caller)
called when exiting operation mode to delete all trains and timetable data etc
Definition: TrainUnit.cpp:9039
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:585
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:10321
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:78
TTrain::MidElement
int MidElement
Definition: TrainUnit.h:337
TTrackElement::TempTrackMarker23
bool TempTrackMarker23
Utility markers for program use.
Definition: TrackUnit.h:140
TInterface::LocationNameKeyUp
void __fastcall LocationNameKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:1236
TInterface::LoadUserGraphicDialog
TOpenDialog * LoadUserGraphicDialog
Definition: InterfaceUnit.h:499
TAllRoutes::CallonVector
std::vector< TCallonEntry > CallonVector
the store of all call-on entries
Definition: TrackUnit.h:1670
TInterface::OutputLog8MouseDown
void __fastcall OutputLog8MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12742
TTrain::LeadElement
int LeadElement
Definition: TrainUnit.h:337
TInterface::SetPausedOrZoomedInfoCaption
void SetPausedOrZoomedInfoCaption(int Caller)
Sets the information panel message for zoom-out or paused modes.
Definition: InterfaceUnit.cpp:20122
TInterface::CurDir
AnsiString CurDir
the full path to the folder where railway.exe resides
Definition: InterfaceUnit.h:933
TInterface::OneEntryTimetableMemoKeyUp
void __fastcall OneEntryTimetableMemoKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4868
TInterface::RouteCancelButton
TBitBtn * RouteCancelButton
Definition: InterfaceUnit.h:204
TPrefDirElement::SetELink
void SetELink(int input)
Used in pasting pref dirs.
Definition: TrackUnit.h:352
TInterface::HomeButton
TBitBtn * HomeButton
Definition: InterfaceUnit.h:259
TRailGraphics
Handles graphic data & functions, single object defined.
Definition: GraphicUnit.h:308
TInterface::OperatorActionPanelDragStartY
int OperatorActionPanelDragStartY
as above for 'Y'
Definition: InterfaceUnit.h:1113
TTrain::RepeatNumber
int RepeatNumber
indicates which of the repeating services this train represents (0 = first service)
Definition: TrainUnit.h:331
TTrainDataEntry::ActionVector
TActionVector ActionVector
all the actions for the train
Definition: TrainUnit.h:204
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:651
TInterface::NewHomeButton
TBitBtn * NewHomeButton
Definition: InterfaceUnit.h:260
TInterface::ResetAll
void ResetAll(int Caller)
Called during ClearEverything and on startup to reset all major railway data values.
Definition: InterfaceUnit.cpp:17874
TInterface::SpeedButton75
TSpeedButton * SpeedButton75
Definition: InterfaceUnit.h:587
TTrainController::LoadSessionLockedRoutes
void LoadSessionLockedRoutes(int Caller, std::ifstream &SessionFile)
load locked routes from a session file
Definition: TrainUnit.cpp:15058
TInterface::DistancesMarked
bool DistancesMarked
true when setting lengths, used to ensure the screen distance markers are redisplayed when the screen...
Definition: InterfaceUnit.h:972
TPrefDirElement::GetXLink
int GetXLink() const
Returns XLink.
Definition: TrackUnit.h:293
TTrainController::EarlyPasses
int EarlyPasses
Definition: TrainUnit.h:781
TTrain::HeadCode
AnsiString HeadCode
needs own HeadCode because repeat entries will differ from TrainDataEntry.HeadCode
Definition: TrainUnit.h:300
TInterface::TrackBuildPanel
TPanel * TrackBuildPanel
'Build/modify railway' panel
Definition: InterfaceUnit.h:365
TTrain::EntryTime
TDateTime EntryTime
Definition: TrainUnit.h:424
TInterface::CutMoving
@ CutMoving
Definition: InterfaceUnit.h:904
TInterface::SelectLengthsMenuItem
TMenuItem * SelectLengthsMenuItem
Definition: InterfaceUnit.h:447
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1386
TInterface::SpeedButton72
TSpeedButton * SpeedButton72
Definition: InterfaceUnit.h:584
TInterface::ValidateTimetableButton
TButton * ValidateTimetableButton
Definition: InterfaceUnit.h:150
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:5981
TUserGraphicItem
Definition: DisplayUnit.h:31
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1530
InterfaceUnit.h
TInterface::CopyMenuItemClick
void __fastcall CopyMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9667
TInterface::PerformanceLogButton
TBitBtn * PerformanceLogButton
Definition: InterfaceUnit.h:206
TInterface::FORMATTEDTT_DIR_NAME
static const UnicodeString FORMATTEDTT_DIR_NAME
Definition: InterfaceUnit.h:887
TInterface::HighLightOneGap
bool HighLightOneGap(int Caller, int &HLoc, int &VLoc)
Called during gap setting to mark a gap with a red ellipse and ask user to select the corresponding g...
Definition: InterfaceUnit.cpp:14364
TTrain::OneLengthAccelDecel
bool OneLengthAccelDecel
set when a train can only move forwards one element before stopping but needs to accelerate for the f...
Definition: TrainUnit.h:367
TTrain::FloatingLabelNextString
AnsiString FloatingLabelNextString(int Caller, TActionVectorEntry *Ptr)
Used in the floating window to display the 'Next' action.
Definition: TrainUnit.cpp:6879
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:636
TTrain::FailedTrainNoFinishJoinMessage
bool FailedTrainNoFinishJoinMessage
Definition: TrainUnit.h:312
TInterface::OperatorActionPanel
TPanel * OperatorActionPanel
new v2.2.0 panel housing the OAListBox with list of trains and times to act
Definition: InterfaceUnit.h:393
TInterface::NextTTEntryButton
TButton * NextTTEntryButton
Definition: InterfaceUnit.h:135
TTextHandler::SelectTextVectorSize
unsigned int SelectTextVectorSize(int Caller)
return the number of items in SelectTextVector
Definition: TextUnit.cpp:544
TInterface::TrackTrainFloat
void TrackTrainFloat(int Caller)
Controls the floating window function, called during the ClockTimer2 function.
Definition: InterfaceUnit.cpp:16294
TDisplay::GetImage
TImage * GetImage()
Return a pointer to the screen image.
Definition: DisplayUnit.h:138
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TInterface::AddLocationNameText
void AddLocationNameText(int Caller, AnsiString Name, int HPos, int VPos, bool UseEnteredPosition)
Add 'Name' to TextVector and display on screen at a position determined by the shape and size of the ...
Definition: InterfaceUnit.cpp:20908
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackVector.at(At)
Definition: TrackUnit.cpp:10430
TTextHandler::CheckTextElementsInFile
bool CheckTextElementsInFile(int Caller, std::ifstream &VecFile)
check the validity of text items in VecFile prior to loading, return true for success
Definition: TextUnit.cpp:366
TInterface::ConverttoRightHandSignalsMenuItemClick
void __fastcall ConverttoRightHandSignalsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13748
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:317
TTrack::GetVLocMax
int GetVLocMax()
Definition: TrackUnit.h:886
TTrainController::LoadSessionContinuationAutoSigEntries
void LoadSessionContinuationAutoSigEntries(int Caller, std::ifstream &SessionFile)
load ContinuationAutoSigEntries from a session file
Definition: TrainUnit.cpp:15141
TInterface::HighlightOneEntryInAllEntriesTTListBox
void HighlightOneEntryInAllEntriesTTListBox(int Caller, int Position)
Called during timetable editing to highlight in red a single entry in the list of all entries in the ...
Definition: InterfaceUnit.cpp:5644
TInterface::DistanceStart
@ DistanceStart
Definition: InterfaceUnit.h:903
TInterface::ErrorMessage
TMemo * ErrorMessage
the text of the normal error message screen
Definition: InterfaceUnit.h:401
TInterface::ExitPrefDirButton
TBitBtn * ExitPrefDirButton
Definition: InterfaceUnit.h:127
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:806
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:126
TInterface::TrackLengthPanel
TPanel * TrackLengthPanel
the panel that contains the distance/speed setting buttons and edit boxes
Definition: InterfaceUnit.h:386
TUtilities::Format96HHMMSS
AnsiString Format96HHMMSS(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm:ss where hh runs from 00 to 95 & resets when...
Definition: Utilities.cpp:581
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3809
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:990
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:991
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:862
TTrainController::OtherMissedEvents
int OtherMissedEvents
Definition: TrainUnit.h:793
TInterface::MoveTextOrGraphicButton
TBitBtn * MoveTextOrGraphicButton
Definition: InterfaceUnit.h:73
TTrainDataEntry::Description
AnsiString Description
headcode is the first train's headcode, rest are calculated from repeat information; ServiceReference...
Definition: TrainUnit.h:188
TInterface::RouteContinuing
@ RouteContinuing
Definition: InterfaceUnit.h:909
TTrain::ExitSpeedHalf
double ExitSpeedHalf
speed when half way into the next element
Definition: TrainUnit.h:389
TTrainController::EarlyExits
int EarlyExits
Definition: TrainUnit.h:782
SignalPost
@ SignalPost
Definition: TrackUnit.h:67
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9392
TTrain::LastActionTime
TDateTime LastActionTime
time of the last timetabled action, used to ensure at least a 30 second delay before the next action
Definition: TrainUnit.h:428
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:17498
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:520
TInterface::InfoPanel
TPanel * InfoPanel
the general information panel (with blue 'i' symbol)
Definition: InterfaceUnit.h:380
TInterface::TextOrUserGraphicGridButtonClick
void __fastcall TextOrUserGraphicGridButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1888
TInterface::FormKeyDown
void __fastcall FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:12161
TInterface::MoveTTEntryDownButton
TButton * MoveTTEntryDownButton
Definition: InterfaceUnit.h:141
TInterface::CheckTimetableFromSessionFile
bool CheckTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
Check the timetable file embedded within a session file & return false for error, called during Sessi...
Definition: InterfaceUnit.cpp:19137
TRailGraphics::SpeedBut71GrndBlackGlyph
Graphics::TBitmap * SpeedBut71GrndBlackGlyph
Definition: GraphicUnit.h:1057
TInterface::DeleteTTEntryButtonClick
void __fastcall DeleteTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4038
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7552
TTrainController::SecondPassActions
bool SecondPassActions(int Caller, bool GiveMessages, bool &TwoLocationFlag)
Carry out further detailed timetable consistency checks, return true for success.
Definition: TrainUnit.cpp:11665
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:6730
TInterface::WarningFlashCount
int WarningFlashCount
increments each clock cycle to a max. of 4 then resets to 0, used to toggle bool WarningFlash - see a...
Definition: InterfaceUnit.h:1155
TInterface::StartWholeRailwayMoveHPos
int StartWholeRailwayMoveHPos
mouse X position when start to move the whole railway
Definition: InterfaceUnit.h:1133
TInterface::SelectedGraphicFileName
AnsiString SelectedGraphicFileName
filename for selected graphic set during LoadGraphic
Definition: InterfaceUnit.h:951
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:8716
TInterface::TrackBuildPanelLabel
TLabel * TrackBuildPanelLabel
label to the left of TrackBuildPanel
Definition: InterfaceUnit.h:323
clNormalBackground
#define clNormalBackground
Definition: GraphicUnit.h:297
TInterface::TTClockAdjButtonClick
void __fastcall TTClockAdjButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13245
TInterface::RAILWAY_DIR_NAME
static const UnicodeString RAILWAY_DIR_NAME
Definition: InterfaceUnit.h:882
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:17483
TInterface::AddTrackButton
TBitBtn * AddTrackButton
Definition: InterfaceUnit.h:69
TInterface::SPADImage
TImage * SPADImage
Definition: InterfaceUnit.h:270
TInterface::OutputLog7MouseDown
void __fastcall OutputLog7MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12732
TInterface::LoadClipboard
void LoadClipboard(int Caller)
Load system clipboard to allow cutting & pasting between separate railway applications.
Definition: InterfaceUnit.cpp:21152
Concourse
@ Concourse
Definition: TrackUnit.h:68
TTextHandler::TTextVectorIterator
std::vector< TTextItem >::iterator TTextVectorIterator
Definition: TextUnit.h:66
TTrainController::SPADRisks
int SPADRisks
Definition: TrainUnit.h:795
TInterface::LocationNamesNotSetImage
TImage * LocationNamesNotSetImage
Definition: InterfaceUnit.h:287
TInterface::FloatingPanel
TPanel * FloatingPanel
new for v2.2.0 where label sits in it and it autosizes to the label. Labels are not TWinControls so t...
Definition: InterfaceUnit.h:390
TRailGraphics::SpeedBut68NormBlackGlyph
Graphics::TBitmap * SpeedBut68NormBlackGlyph
Definition: GraphicUnit.h:1046
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:815
TInterface::SaveMenuItemClick
void __fastcall SaveMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2659
TInterface::ScreenGridButtonClick
void __fastcall ScreenGridButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1998
TTrain::EntrySpeed
double EntrySpeed
speed at which the train enters the next element
Definition: TrainUnit.h:387
TInterface::UserGraphicMoveHPos
int UserGraphicMoveHPos
Definition: InterfaceUnit.h:1153
TInterface::PassRedSignalMenuItemClick
void __fastcall PassRedSignalMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11778
TInterface::ReselectMenuItem
TMenuItem * ReselectMenuItem
Definition: InterfaceUnit.h:439
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:13550
TInterface::ClearEverything
bool ClearEverything(int Caller)
First check whether a railway file has changed and if so ask user if really wants to close it without...
Definition: InterfaceUnit.cpp:14400
TInterface::PrefDirContinuing
@ PrefDirContinuing
Definition: InterfaceUnit.h:898
TTrain::TrainGone
bool TrainGone
set when train has left the railway, so it can be removed from the display at the next clock tick
Definition: TrainUnit.h:438
TRailGraphics::SpeedBut70NormBlackGlyph
Graphics::TBitmap * SpeedBut70NormBlackGlyph
Definition: GraphicUnit.h:1048
TTrainController::OnTimePasses
int OnTimePasses
Definition: TrainUnit.h:791
TInterface::SaveAsMenuItem
TMenuItem * SaveAsMenuItem
Definition: InterfaceUnit.h:419
TInterface::MoveTextOrGraphicButtonClick
void __fastcall MoveTextOrGraphicButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1153
TTrainController::SigSHigh
bool SigSHigh
Definition: TrainUnit.h:756
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4516
TInterface::ZoomButton
TBitBtn * ZoomButton
Definition: InterfaceUnit.h:261
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1858
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:95
TInterface::CopyTTEntryButton
TButton * CopyTTEntryButton
Definition: InterfaceUnit.h:136
TInterface::ErrorMessageStoreImage
TMemo * ErrorMessageStoreImage
the text of the error message for failure to draw trains in SaveOperatingImage
Definition: InterfaceUnit.h:403
TTrain::StoppedAfterSPAD
bool StoppedAfterSPAD
Definition: TrainUnit.h:442
TInterface::NoPrefDirMode
@ NoPrefDirMode
Definition: InterfaceUnit.h:898
TTrainController::OnTimeArrivals
int OnTimeArrivals
Definition: TrainUnit.h:789
TInterface::MoveTTEntryDownButtonClick
void __fastcall MoveTTEntryDownButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4555
TInterface::PerformanceLogBox
TMemo * PerformanceLogBox
the performance log displayed during operation
Definition: InterfaceUnit.h:407
TRailGraphics::SpeedBut72GrndBlackGlyph
Graphics::TBitmap * SpeedBut72GrndBlackGlyph
Definition: GraphicUnit.h:1058
TAllRoutes::LevelCrossingBarrierUpDelay
const float LevelCrossingBarrierUpDelay
the full value in seconds for which the level crossing flashes prior to closing to trains
Definition: TrackUnit.h:1690
TInterface::SpeedTopLabel
TLabel * SpeedTopLabel
Definition: InterfaceUnit.h:186
TInterface::OperateButton
TBitBtn * OperateButton
Definition: InterfaceUnit.h:200
clFrontCodeSignaller
#define clFrontCodeSignaller
Definition: GraphicUnit.h:295
TInterface::SignallerJoinedByMenuItemClick
void __fastcall SignallerJoinedByMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11593
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:780
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TActionVectorEntry::ArrivalTime
TDateTime ArrivalTime
Definition: TrainUnit.h:115
TTrain::StoppedAtBuffers
bool StoppedAtBuffers
Definition: TrainUnit.h:442
TInterface::SkipFormResizeEvent
bool SkipFormResizeEvent
added at v2.1.0 to avoid calling the event during startup and shutdown
Definition: InterfaceUnit.h:1026
TTrainController::CreateTTAnalysisFile
bool CreateTTAnalysisFile(int Caller, AnsiString RailwayTitle, AnsiString TimetableTitle, AnsiString CurDir, bool ArrChecked, bool DepChecked, bool AtLocChecked, bool DirChecked, int ArrRange, int DepRange)
Generate a timetable analysis file in the 'Formatted Timetables' folder, return false if failed for a...
Definition: TrainUnit.cpp:15938
TTrain::Mass
int Mass
in kg
Definition: TrainUnit.h:418
TInterface::TrackInfoOnOffMenuItem
TMenuItem * TrackInfoOnOffMenuItem
Definition: InterfaceUnit.h:454
TDisplay::ShowWarningLog
void ShowWarningLog(int Caller)
Show the warnings after timetable clock adjusted.
Definition: DisplayUnit.cpp:567
TTrainController::ProcessOneTimetableLine
bool ProcessOneTimetableLine(int Caller, int Count, AnsiString OneLine, bool &EndOfFile, bool FinalCall, bool GiveMessages, bool CheckLocationsExistInRailway)
Carry out preliminary (mainly syntax) validity checks on a single timetable service entry and (if Fin...
Definition: TrainUnit.cpp:9939
TInterface::SaveAsMenuItemClick
void __fastcall SaveAsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2712
TTextItem
A single piece of text that can be displayed on the railway.
Definition: TextUnit.h:36
TInterface::PointFlash
TGraphicElement * PointFlash
Definition: InterfaceUnit.h:1168
TInterface::TrackLinkedImage
TImage * TrackLinkedImage
Definition: InterfaceUnit.h:282
TTrain::LeadExitPos
int LeadExitPos
Definition: TrainUnit.h:337
TInterface::SelectPickedUp
bool SelectPickedUp
true when a valid selected screen area has been clicked after a 'Copy' or 'Cut' selected in the 'Edit...
Definition: InterfaceUnit.h:1020
TDisplay::ResetZoomOutOffsets
void ResetZoomOutOffsets()
Reset the zoomed-out screen display to the 'Home' position.
Definition: DisplayUnit.h:208
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:159
TInterface::DevelopmentPanel
TPanel * DevelopmentPanel
used for diagnostic purposes, made visible by ctrl+ alt+ 3
Definition: InterfaceUnit.h:388
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1877
TInterface::PerformancePanel
TPanel * PerformancePanel
displays the operating performance log
Definition: InterfaceUnit.h:382
TTrainController::DerailWarning
bool DerailWarning
Definition: TrainUnit.h:742
TInterface::CopyMoving
@ CopyMoving
Definition: InterfaceUnit.h:904
TInterface::TimetableEditPanel
TPanel * TimetableEditPanel
the large panel that contains all the main timetable components
Definition: InterfaceUnit.h:374
TInterface::RouteMode
enum TInterface::@0 RouteMode
route building modes
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:90
TInterface::TrainStatusInfoOnOffMenuItem
TMenuItem * TrainStatusInfoOnOffMenuItem
Definition: InterfaceUnit.h:456
TInterface::SetLengthsButtonClick
void __fastcall SetLengthsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1440
TInterface::SaveTTEntryButton
TButton * SaveTTEntryButton
Definition: InterfaceUnit.h:142
TInterface::BaseMode
@ BaseMode
Definition: InterfaceUnit.h:871
TInterface::SpeedEditBoxKeyUp
void __fastcall SpeedEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:12936
TTrack::TTrackMap
std::map< THVPair, unsigned int, TMapComp > TTrackMap
map of TrackElement TrackVectorPositions, HLoc & VLoc pair is the key
Definition: TrackUnit.h:670
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:11153
TInterface::MirrorMenuItem
TMenuItem * MirrorMenuItem
Definition: InterfaceUnit.h:443
TInterface::EveryPrefDir
TOnePrefDir * EveryPrefDir
all the Pref Dir elements in the railway
Definition: InterfaceUnit.h:1179
TTrainController::TotLateDepMins
float TotLateDepMins
Definition: TrainUnit.h:773
TDisplay::ZoomOutFlag
bool ZoomOutFlag
true when zoomed-out
Definition: DisplayUnit.h:69
TInterface::OutputLog8
TLabel * OutputLog8
Definition: InterfaceUnit.h:307
TTrainController::TrainVector
TTrainVector TrainVector
vector containing all trains currently in the railway
Definition: TrainUnit.h:826
TInterface::SaveAsSubroutine
void SaveAsSubroutine(int Caller)
Used to save a railway when not already saved - e.g. when not already named or when the 'Save as' men...
Definition: InterfaceUnit.cpp:20635
TInterface::MainScreenMouseDown2
void MainScreenMouseDown2(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
Called when mouse button clicked in zoom-in mode.
Definition: InterfaceUnit.cpp:5990
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1536
TInterface::RepairFailedTrainMenuItemClick
void __fastcall RepairFailedTrainMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11683
TInterface::AddLocationName
@ AddLocationName
Definition: InterfaceUnit.h:903
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8513
TTrack::IsTrackFinished
bool IsTrackFinished()
Indicates whether or not the track has been successfully linked together.
Definition: TrackUnit.h:837
TAllRoutes::AllRoutesClear
void AllRoutesClear()
Erases all routes from AllRoutesVector and from Route2MultiMap.
Definition: TrackUnit.h:1718
TRailGraphics::SpeedBut74GrndBlackGlyph
Graphics::TBitmap * SpeedBut74GrndBlackGlyph
Definition: GraphicUnit.h:1060
TAllRoutes::PointsDelay
const float PointsDelay
the value in seconds for which points flash prior to being changed. Used for the points flash period ...
Definition: TrackUnit.h:1694
TInterface::SaveSession
void SaveSession(int Caller)
Save a session file - see LoadSession for details of additions to the session file.
Definition: InterfaceUnit.cpp:18085
TTrack::GetTrackElementFromAnyTrackMap
TTrackElement & GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector)
Return a reference to the element at HLoc & VLoc for any map and any vector (used for SelectPrefDir i...
Definition: TrackUnit.cpp:5660
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TAllRoutes::SignalsDelay
const float SignalsDelay
the value in seconds for which signals flash prior to being changed. Used for the route flash period ...
Definition: TrackUnit.h:1696
TDisplay::GetFont
TFont * GetFont()
Return the current screen font.
Definition: DisplayUnit.h:132
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:294
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1312
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:862
TTrainController::TotEarlyArrMins
float TotEarlyArrMins
values for performance file summary
Definition: TrainUnit.h:768
TInterface::PerformancePanelStartDrag
void __fastcall PerformancePanelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:5909
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:13024
TInterface::TempCursorSet
bool TempCursorSet
indicates that a screen cursor has been stored in TempCursor for redisplay after a temporary cursor (...
Definition: InterfaceUnit.h:1028
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:12159
TInterface::PasteMenuItemClick
void __fastcall PasteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10638
TInterface::MainScreenMouseUp
void __fastcall MainScreenMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:7903
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TInterface::SaveTempTimetableFile
void SaveTempTimetableFile(int Caller, AnsiString InFileName)
Save a timetable as a temporary file either on loading directly or on loading a session file....
Definition: InterfaceUnit.cpp:20380
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1700
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TInterface::RotateMenuItemClick
void __fastcall RotateMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9927
TTrainDataEntry::SignallerSpeed
int SignallerSpeed
in km/h for use when under signaller control
Definition: TrainUnit.h:200
TInterface::OverallDistance
int OverallDistance
Definition: InterfaceUnit.h:1115
TTrain::AbleToMove
bool AbleToMove(int Caller)
Indicates that a train is not prevented from moving - used to allow appropriate popup menu options wh...
Definition: TrainUnit.cpp:6735
TTrainController::MTBFHours
double MTBFHours
Mean time between failures in timetable clock hours.
Definition: TrainUnit.h:759
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:12652
TInterface::RestoreAllDefaultLengthsButtonClick
void __fastcall RestoreAllDefaultLengthsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1797
TInterface::LengthWarningSentFlag
bool LengthWarningSentFlag
indicates that the length selection applying to all elements in the selection warning has been given,...
Definition: InterfaceUnit.h:982
TInterface::FlipMenuItemClick
void __fastcall FlipMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9688
TInterface::api_main_mode_
int api_main_mode_
Definition: InterfaceUnit.h:919
TInterface::TrainTTInfoOnOffMenuItem
TMenuItem * TrainTTInfoOnOffMenuItem
Definition: InterfaceUnit.h:457
TInterface::AllSetUpFlag
bool AllSetUpFlag
false during initial start up, true when all set up to allow MasterClock to start
Definition: InterfaceUnit.h:954
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3619
TInterface::LocationNameButton
TBitBtn * LocationNameButton
Definition: InterfaceUnit.h:74
TTrain::TrainMode
TTrainMode TrainMode
mode of operation - either Timetable (running under timetable control) or Signaller (running under si...
Definition: TrainUnit.h:430
TInterface::LoadRailway
void LoadRailway(int Caller, AnsiString LoadFileName)
Load a railway file. The Active elements marker now has a '1' at the end if there are user graphics t...
Definition: InterfaceUnit.cpp:2506
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:11196
TInterface::TextOrUserGraphicGridButton
TBitBtn * TextOrUserGraphicGridButton
Definition: InterfaceUnit.h:76
TInterface::PointFlashVectorPosition
int PointFlashVectorPosition
Definition: InterfaceUnit.h:1122
TInterface::AddSubMinsBoxKeyUp
void __fastcall AddSubMinsBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4893
TInterface::ExitOperationButtonClick
void __fastcall ExitOperationButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2407
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1760
TInterface::TTClockAdd1hButtonClick
void __fastcall TTClockAdd1hButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13493
TUtilities::Format96HHMM
AnsiString Format96HHMM(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm where hh runs from 00 to 95 & resets when it...
Definition: Utilities.cpp:600
TInterface::TTClockx2ButtonClick
void __fastcall TTClockx2ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13321
TInterface::PerformancePanelDragStartX
int PerformancePanelDragStartX
mouse 'X' position when the performance panel begins to be dragged
Definition: InterfaceUnit.h:1118
TInterface::SpeedEditBox2KeyUp
void __fastcall SpeedEditBox2KeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:13092
TInterface::SavedFileName
AnsiString SavedFileName
the full path and filename of the loaded railway
Definition: InterfaceUnit.h:945
TInterface::FillSelectionMessageSentFlag
bool FillSelectionMessageSentFlag
indicates that the message about filling a selected area with a chosen track element has been given,...
Definition: InterfaceUnit.h:978
TInterface::PlanPrefDirsMenuItemClick
void __fastcall PlanPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2025
TInterface::OperatingPanel
TPanel * OperatingPanel
'Operate railway' panel
Definition: InterfaceUnit.h:371
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:927
TInterface::ShowOperatorActionPanel
bool ShowOperatorActionPanel
true when the 'trains needing action' button has been clicked during operation (new at v2....
Definition: InterfaceUnit.h:1048
TTrack::GetGapVLoc
int GetGapVLoc()
Definition: TrackUnit.h:871
TUtilities::CheckFileString
bool CheckFileString(std::ifstream &InFile)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success
Definition: Utilities.cpp:399
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:1009
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:12472
TRailGraphics::bmGrid
Graphics::TBitmap * bmGrid
Definition: GraphicUnit.h:522
TInterface::RestoreFocusPanel
TPanel * RestoreFocusPanel
Panel used to restore focus to Interface to enable cursor keys to move screen.
Definition: InterfaceUnit.h:362
TInterface::BlackBgndMenuItem
TMenuItem * BlackBgndMenuItem
Definition: InterfaceUnit.h:434
SignallerControlStop
@ SignallerControlStop
Definition: TrainUnit.h:52
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:815
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:640
TInterface::FloatingLabel
TLabel * FloatingLabel
the floating window that displays track & train information
Definition: InterfaceUnit.h:343
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11347
TInterface::NewTTEntryButton
TButton * NewTTEntryButton
Definition: InterfaceUnit.h:144
TTrainController::ExcessLCDownMins
float ExcessLCDownMins
total excess time in minutes over the 3 minutes barriers down allowance for level crossings
Definition: TrainUnit.h:766
TInterface::SubMinsButtonClick
void __fastcall SubMinsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3785
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:445
TInterface::TimetableControlMenuItemClick
void __fastcall TimetableControlMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11367
TTrack::TActiveTrackElementNameIterator
TActiveTrackElementNameMap::iterator TActiveTrackElementNameIterator
Definition: TrackUnit.h:719
TInterface::DistanceBox
TEdit * DistanceBox
distance/speed setting edit box that accepts distances
Definition: InterfaceUnit.h:96
TInterface::PresetAutoSigRoutesButton
TBitBtn * PresetAutoSigRoutesButton
Definition: InterfaceUnit.h:205
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:136
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TInterface::TTServiceSyntaxCheckButtonClick
void __fastcall TTServiceSyntaxCheckButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4401
TInterface::TTClockSpeed
float TTClockSpeed
rate at which the timetable clock runs 1 = normal
Definition: InterfaceUnit.h:1090
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:54
TDisplay::PlotAbsolute
void PlotAbsolute(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Definition: DisplayUnit.cpp:489
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5708
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1794
TInterface::TTClockx4ButtonClick
void __fastcall TTClockx4ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13340
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:13488
TTextHandler::TextFound
bool TextFound(int Caller, int HPosInput, int VPosInput, AnsiString &Text)
look for a text item in the vicinity of HPosInput & VPosInput, return true if found & return the foun...
Definition: TextUnit.cpp:240
TInterface::LCManualLowerBarriersMessageSent
bool LCManualLowerBarriersMessageSent
indicates that the manual LC operation message has been given, so it won't be given again
Definition: InterfaceUnit.h:980
TInterface::SaveImageAndPrefDirsMenuItemClick
void __fastcall SaveImageAndPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2918
TInterface::AddMinsButton
TButton * AddMinsButton
Definition: InterfaceUnit.h:147
SignallerStepForward
@ SignallerStepForward
Definition: TrainUnit.h:52
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:881
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:555
TInterface::TrackInfoOnOffMenuItemClick
void __fastcall TrackInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5763
TInterface::RecoverClipboard
void RecoverClipboard(int Caller, bool &ValidResult)
Recovers clipboard as track and text vectors.
Definition: InterfaceUnit.cpp:21366
TTrainController::LateExits
int LateExits
Definition: TrainUnit.h:787
TTrainController::OpTimeToActUpdateCounter
unsigned int OpTimeToActUpdateCounter
<List of all ServiceRefs that have two or more same locations without a cdt between - loaded during S...
Definition: TrainUnit.h:810
TTrain::BeingCalledOn
bool BeingCalledOn
in course of being called on to a station
Definition: TrainUnit.h:351
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:238
TInterface::AZOrderButtonClick
void __fastcall AZOrderButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5274
TInterface::CopySelected
bool CopySelected
used to indicate whether copy or cut selected in edit menu - for clipboard pasting
Definition: InterfaceUnit.h:966
TInterface::HiddenScreen
TImage * HiddenScreen
a hidden copy of the railway display screen used during ClearandRebuildRailway (see below) to avoid f...
Definition: InterfaceUnit.h:1174
TInterface::PerformancePanelLabelStartDrag
void __fastcall PerformancePanelLabelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:12068
TInterface::LoadPerformanceFile
void LoadPerformanceFile(int Caller, std::ifstream &InFile)
Load the performance file part of a sessionfile.
Definition: InterfaceUnit.cpp:19927
TInterface::CPCancelButtonClick
void __fastcall CPCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14043
TInterface::OutputLog4MouseDown
void __fastcall OutputLog4MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12703
TInterface::AddGraphic
@ AddGraphic
Definition: InterfaceUnit.h:903
TInterface::SetLevel1Mode
void SetLevel1Mode(int Caller)
Sets the Level1 user mode, using the Level1Mode variable to determine the mode.
Definition: InterfaceUnit.cpp:14644
TInterface::NewHomeButtonClick
void __fastcall NewHomeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9510
TInterface::OutputLog4
TLabel * OutputLog4
Definition: InterfaceUnit.h:303
TInterface::FontDialog
TFontDialog * FontDialog
font change dialog
Definition: InterfaceUnit.h:504
TInterface::TwoLocationNamePanelHide
bool TwoLocationNamePanelHide
true if user opts not to show the two location name warning (false on starting the program)
Definition: InterfaceUnit.h:1034
TInterface::TrackSelecting
@ TrackSelecting
Definition: InterfaceUnit.h:904
TTrainController::TotLateArrMins
float TotLateArrMins
Definition: TrainUnit.h:772
TInterface::Level2PrefDirMode
enum TInterface::TLevel2PrefDirMode Level2PrefDirMode
TInterface::OperatingPanelLabel
TLabel * OperatingPanelLabel
displays 'Operation' or 'Disabled' on the operating panel during operation for running or paused
Definition: InterfaceUnit.h:331
TInterface::DivergingPointVectorPosition
int DivergingPointVectorPosition
Definition: InterfaceUnit.h:1122
TInterface::OAListBoxMouseUp
void __fastcall OAListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:4987
TTrainController::PlotAllTrainsInZoomOutMode
void PlotAllTrainsInZoomOutMode(int Caller, bool Flash)
Plots all trains on screen in zoomed-out mode, state of 'Flash' determines whether the flashing train...
Definition: TrainUnit.cpp:15294
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1486
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8480
TInterface::SavePerformanceFile
void SavePerformanceFile(int Caller, std::ofstream &OutFile)
Save performance file part of a session file.
Definition: InterfaceUnit.cpp:19990
TTextItem::Font
TFont * Font
the text font
Definition: TextUnit.h:52
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1641
TTrain::SignallerStopped
bool SignallerStopped
Definition: TrainUnit.h:442
API::dump
void dump()
save currently recorded status data to INI file
Definition: API.cpp:37
TDisplay::SetFont
void SetFont(TFont *Font)
Set the screen font to 'Font'.
Definition: DisplayUnit.h:215
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:17337
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1630
TTrain::TrainDataEntryPtr
TTrainDataEntry * TrainDataEntryPtr
points to the current position in the timetable's TrainDataVector
Definition: TrainUnit.h:343
TTrainDataEntry::StartSpeed
int StartSpeed
in km/h
Definition: TrainUnit.h:202
TTrainDataEntry::NumberOfTrains
int NumberOfTrains
number of repeats + 1
Definition: TrainUnit.h:198
TTrainController::Derailments
int Derailments
Definition: TrainUnit.h:779
clStationStopBackground
#define clStationStopBackground
Definition: GraphicUnit.h:301
TInterface::AZOrderButton
TButton * AZOrderButton
Definition: InterfaceUnit.h:146
Crossover
@ Crossover
Definition: TrackUnit.h:67
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6188
TInterface::SignallerJoinedByMenuItem
TMenuItem * SignallerJoinedByMenuItem
Definition: InterfaceUnit.h:486
Interface
TInterface * Interface
Definition: InterfaceUnit2.10.0.cpp:69
TRailGraphics::SpeedBut69NormBlackGlyph
Graphics::TBitmap * SpeedBut69NormBlackGlyph
Definition: GraphicUnit.h:1047
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7193
TDisplay::ResetZoomInOffsets
void ResetZoomInOffsets()
Reset the zoomed-in screen display to the 'Home' position.
Definition: DisplayUnit.h:201
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:9855
TInterface::RotRightMenuItem
TMenuItem * RotRightMenuItem
Definition: InterfaceUnit.h:484
AtLocation
@ AtLocation
Definition: TrainUnit.h:70
TInterface::ExportTTButton
TButton * ExportTTButton
Definition: InterfaceUnit.h:154
DefaultTrackLength
#define DefaultTrackLength
Definition: TrackUnit.h:37
Signal
@ Signal
Definition: TrackUnit.h:77
TPrefDirElement::GetSignedIntTrackVectorPosition
int GetSignedIntTrackVectorPosition() const
Returns signed integer value of TrackVectorPosition (used in flip, mirror etc for pref dirs) added at...
Definition: TrackUnit.h:323
TInterface::TimetableChangedFlag
bool TimetableChangedFlag
true when a timetable in the editor has changed (used to warn user if opts to exit without saving)
Definition: InterfaceUnit.h:1042
TInterface::SaveTimetableToErrorFile
bool SaveTimetableToErrorFile(int Caller, std::ofstream &ErrorFile, AnsiString ErrorFileStr, AnsiString TimetableFileName)
Called when compiling the error log file, to save the loaded timetable if any and the timetable being...
Definition: InterfaceUnit.cpp:18930
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:787
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17787
TTrackElement::TrainIDOnBridgeTrackPos01
int TrainIDOnBridgeTrackPos01
Definition: TrackUnit.h:154
TInterface::TrainHeadCodeMenuItem
TMenuItem * TrainHeadCodeMenuItem
Definition: InterfaceUnit.h:468
TTrainController::TrainDataVector
TTrainDataVector TrainDataVector
vector containing the internal timetable
Definition: TrainUnit.h:824
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:12522
TAllRoutes::NotAutoSigsRoute
@ NotAutoSigsRoute
Definition: TrackUnit.h:1631
TTrain::ExitTimeHalf
TDateTime ExitTimeHalf
Definition: TrainUnit.h:424
TPrefDirElement::SetEntryDirectionGraphicPtr
void SetEntryDirectionGraphicPtr(Graphics::TBitmap *input)
Used in pasting pref dirs.
Definition: TrackUnit.h:388
Exited
@ Exited
Definition: TrainUnit.h:86
TInterface::OutputLog2
TLabel * OutputLog2
Definition: InterfaceUnit.h:301
TInterface::SpeedButton74
TSpeedButton * SpeedButton74
Definition: InterfaceUnit.h:586
TInterface::TTClockAdjustWarningLabel
TLabel * TTClockAdjustWarningLabel
Definition: InterfaceUnit.h:236
TInterface::ScreenRightButtonClick
void __fastcall ScreenRightButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9133
TInterface::PositionalPanel
TPanel * PositionalPanel
Definition: InterfaceUnit.h:392
TInterface::StepForwardMenuItemClick
void __fastcall StepForwardMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11821
TInterface::ErrorLog
void ErrorLog(int Caller, AnsiString Message)
The error logging routine, called when an error is detected.
Definition: InterfaceUnit.cpp:17734
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackVector.at(At)
Definition: TrackUnit.cpp:10416
TTrainController::LoadSessionTrains
void LoadSessionTrains(int Caller, std::ifstream &SessionFile)
load trains from a session file
Definition: TrainUnit.cpp:14992
TInterface::UserGraphicFoundFlag
bool UserGraphicFoundFlag
indicates that a user graphic item has been found when clicking on a build screen for moving
Definition: InterfaceUnit.h:1040
TInterface::RouteCancelButtonClick
void __fastcall RouteCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2358
TInterface::SelectedTrainID
int SelectedTrainID
used to store the train ID when right clicked for signaller control actions
Definition: InterfaceUnit.h:1131
TTextHandler::SelectTextPtrAt
TTextItem * SelectTextPtrAt(int Caller, int At)
return the text item at position 'At' in SelectTextVector (carries out range checking)
Definition: TextUnit.cpp:570
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:792
TInterface::FlashingGraphics
void FlashingGraphics(int Caller, TDateTime Now)
Deal with any warning graphics that need to flash (call on, signal stop, crash etc),...
Definition: InterfaceUnit.cpp:17101
TInterface::ScreenLeftButton
TBitBtn * ScreenLeftButton
Definition: InterfaceUnit.h:256
TInterface::CheckPrefDirConflictsMenuItem
TMenuItem * CheckPrefDirConflictsMenuItem
Definition: InterfaceUnit.h:450
TTrain::StoppedAtLocation
bool StoppedAtLocation
Definition: TrainUnit.h:442
TTrainController::TContinuationTrainExpectationMultiMapIterator
TContinuationTrainExpectationMultiMap::iterator TContinuationTrainExpectationMultiMapIterator
iterator for the multimap
Definition: TrainUnit.h:702
TInterface::TTClockx16ButtonClick
void __fastcall TTClockx16ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13378
TInterface::OAListBoxMouseDown
void __fastcall OAListBoxMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:5056
TInterface::BuildTrackMenuItem
TMenuItem * BuildTrackMenuItem
Definition: InterfaceUnit.h:428
TInterface::SaveOperatingImageMenuItem
TMenuItem * SaveOperatingImageMenuItem
Definition: InterfaceUnit.h:463
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:744
TInterface::NoRailway
bool NoRailway()
Returns true if there are no track elements and no text.
Definition: InterfaceUnit.cpp:20869
TInterface::AllEntriesTTListBox
TListBox * AllEntriesTTListBox
the list of service entries displayed on the left hand side of the timetable edit screen
Definition: InterfaceUnit.h:412
TInterface::CallingOnButtonClick
void __fastcall CallingOnButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9041
TInterface::SaveTTDialog
TSaveDialog * SaveTTDialog
Definition: InterfaceUnit.h:503
TInterface::DeleteOnePrefDirButtonClick
void __fastcall DeleteOnePrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2102
TAllRoutes::NextRouteID
int NextRouteID
stores the value for the route ID number that is next to be built
Definition: TrackUnit.h:1698
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success and re...
Definition: Utilities.cpp:529
TInterface::TTEntryChangedFlag
bool TTEntryChangedFlag
true when a timetable entry that is displayed in the timetable entry edit window has changed
Definition: InterfaceUnit.h:1050
TInterface::HighlightPanel
TPanel * HighlightPanel
the orange bar that displays the current timetable entry in AllEntriesTTListBox
Definition: InterfaceUnit.h:378
TInterface::MoveTTEntryUpButtonClick
void __fastcall MoveTTEntryUpButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4493
TInterface::SpeedBottomLabel
TLabel * SpeedBottomLabel
Definition: InterfaceUnit.h:187
TInterface::CheckPrefDirConflictsMenuItemClick
void __fastcall CheckPrefDirConflictsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10812
TTrainController::BFHigh
bool BFHigh
Definition: TrainUnit.h:756
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TInterface::TTClockResetButtonClick
void __fastcall TTClockResetButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13553
TInterface::ClockLabel
TLabel * ClockLabel
the timetable clock
Definition: InterfaceUnit.h:329
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:14318
TTrain::LagEntryPos
int LagEntryPos
Definition: TrainUnit.h:337
TInterface::SetTrackBuildImages
void SetTrackBuildImages(int Caller)
Sets the left screen images (track linked or not, gaps set or not, locations named or not) during rai...
Definition: InterfaceUnit.cpp:17986
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4117
TInterface::AddText
@ AddText
Definition: InterfaceUnit.h:903
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2339
TTrainController::UnexpectedExits
int UnexpectedExits
Definition: TrainUnit.h:797
TInterface::LoadTimetableMenuItemClick
void __fastcall LoadTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11231
TInterface::LengthEditKeyUp
void __fastcall LengthEditKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:13160
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:12290
TInterface::OutputLog1
TLabel * OutputLog1
Definition: InterfaceUnit.h:300
TTrain::LeavingUnderSigControlAtContinuation
bool LeavingUnderSigControlAtContinuation
set when the train has reached an exit continuation when under signaller control, used to prevent the...
Definition: TrainUnit.h:365
TInterface::GetTrainFloatingInfoFromContinuation
void GetTrainFloatingInfoFromContinuation(int Caller, int VecPos, AnsiString FormatNoDPStr, AnsiString SpecialStr, AnsiString &TrainStatusFloat, AnsiString &TrainTTFloat)
Called when floating train info needed and train hasn't entered yet.
Definition: InterfaceUnit.cpp:16735
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:954
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5684
TInterface::AddSubMinsBox
TEdit * AddSubMinsBox
the edit box that accepts minutes to add or subtract
Definition: InterfaceUnit.h:181
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:18988
TInterface::TTClockExitButton
TButton * TTClockExitButton
Definition: InterfaceUnit.h:224
TInterface::SpeedEditBox2
TEdit * SpeedEditBox2
Definition: InterfaceUnit.h:107
API::add_metadata_int
void add_metadata_int(const AnsiString &label, int *data)
add pointer to integer variable to monitor value
Definition: API.cpp:32
TInterface::MoveForwardsMenuItemClick
void __fastcall MoveForwardsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11534
TTrack::Down
@ Down
Definition: TrackUnit.h:625
TTrainController::TwoOrMoreLocationsWarningGiven
bool TwoOrMoreLocationsWarningGiven
new at v2.6.0 to allow loops
Definition: TrainUnit.h:752
TInterface::TimetableNameLabel
TLabel * TimetableNameLabel
displays the current timetable name on the timetable edit panel
Definition: InterfaceUnit.h:319
TInterface::SpeedBottomLabel2
TLabel * SpeedBottomLabel2
Definition: InterfaceUnit.h:118
TInterface::IsPerformancePanelObscuringFloatingLabel
bool IsPerformancePanelObscuringFloatingLabel(int Caller)
Checked during operation, returns true if so and PerformancePanel removed - not used from v2....
Definition: InterfaceUnit.cpp:17816
TimeTimeLoc
@ TimeTimeLoc
Definition: TrainUnit.h:64
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1517
TInterface::TimetableChangedInAZOrderFlag
bool TimetableChangedInAZOrderFlag
used to give a warning message that changes will be discarded if proceed
Definition: InterfaceUnit.h:1046
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:6891
TInterface::AddTrackButtonClick
void __fastcall AddTrackButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:929
TInterface::DeleteMenuItemClick
void __fastcall DeleteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10657
TTrain::Derailed
bool Derailed
Definition: TrainUnit.h:442
TInterface::MMoveTextGraphicUserGraphicFoundFlag
bool MMoveTextGraphicUserGraphicFoundFlag
Mouse move flags to prevent repeated event logs.
Definition: InterfaceUnit.h:992
TInterface::ConflictAnalysisButton
TButton * ConflictAnalysisButton
Definition: InterfaceUnit.h:239
TTextHandler::TextVectorPush
void TextVectorPush(int Caller, TTextItem Text)
push &Text onto TextVector & reset the size of the railway if necessary
Definition: TextUnit.cpp:505
TInterface::TTClockAdjButton
TBitBtn * TTClockAdjButton
Definition: InterfaceUnit.h:210
TInterface::PowerEditBoxKeyUp
void __fastcall PowerEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:13025
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:17429
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:673
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7266
TTrainController::SaveSessionLockedRoutes
void SaveSessionLockedRoutes(int Caller, std::ofstream &SessionFile)
save locked routes to a session file
Definition: TrainUnit.cpp:15041
API::add_metadata_str
void add_metadata_str(const AnsiString &label, AnsiString *data)
add pointer to string variable to monitor value
Definition: API.cpp:22
TInterface::OpenHelpMenuItemClick
void __fastcall OpenHelpMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12793
TTrain::OriginalPowerAtRail
double OriginalPowerAtRail
new at v2.4.0 to store value before a failure so it can be restored from here when repaired
Definition: TrainUnit.h:408
TInterface::CheckPerformanceFile
bool CheckPerformanceFile(int Caller, std::ifstream &InFile)
Check the performance file embedded within a session file & return false for error,...
Definition: InterfaceUnit.cpp:19959
TInterface::TInterface
__fastcall TInterface(TComponent *Owner)
constructor
Definition: InterfaceUnit.cpp:84
clB4G5R5
#define clB4G5R5
Definition: GraphicUnit.h:244
TInterface::TooLongMessageSentFlag
bool TooLongMessageSentFlag
indicates that the length of a location element might be too long (>200m), so it won't be given again
Definition: InterfaceUnit.h:1036
Timetable
@ Timetable
Definition: TrainUnit.h:58
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TInterface
Definition: InterfaceUnit.h:62
TTextHandler::SetFontStyleFromInt
TFontStyles SetFontStyleFromInt(int Caller, int Input)
used in loading from a file
Definition: TextUnit.cpp:126
TInterface::RemoveTrainMenuItemClick
void __fastcall RemoveTrainMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11868
TInterface::RotRightMenuItemClick
void __fastcall RotRightMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10066
TTrain::AbleToMoveButForSignal
bool AbleToMoveButForSignal(int Caller)
Indicates that a train is only prevented from moving by a signal - used to allow appropriate popup me...
Definition: TrainUnit.cpp:6790
TTrainController::OpActionPanelVisible
bool OpActionPanelVisible
new v2.2.0 flag to prevent time to act functions when not visible
Definition: TrainUnit.h:750
TInterface::SaveInterface
void SaveInterface(int Caller, std::ofstream &SessionFile)
Save interface part of a session file.
Definition: InterfaceUnit.cpp:18507
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:632
TInterface::AcceptDragging
void __fastcall AcceptDragging(TObject *Sender, TObject *Source, int X, int Y, TDragState State, bool &Accept)
Definition: InterfaceUnit.cpp:5834
Parapet
@ Parapet
Definition: TrackUnit.h:68
TTrack::GapFlashRedPosition
int GapFlashRedPosition
TrackVectorPosition of the gap element that is flashing green or red.
Definition: TrackUnit.h:778
HiddenDisplay
TDisplay * HiddenDisplay
The object pointer for the internal hidden display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:54
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:17456
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:65
TInterface::RouteFlashDuration
float RouteFlashDuration
duration of the route flash period
Definition: InterfaceUnit.h:1088
TTrainController::SignalStopWarning
bool SignalStopWarning
Definition: TrainUnit.h:742
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:287
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:8997
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:17402
TDisplay::PerformanceLog
void PerformanceLog(int Caller, AnsiString Statement)
Send Statement to the performance log on screen and to the file.
Definition: DisplayUnit.cpp:521
TTrain::SignallerStopBrakeRate
double SignallerStopBrakeRate
the train brake rate when stopping under signaller control
Definition: TrainUnit.h:403
TTrainController::SignallerTrainRemovedOnAutoSigsRoute
bool SignallerTrainRemovedOnAutoSigsRoute
true if train was on an AutoSigsRoute when removed by the signaller
Definition: TrainUnit.h:748
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:815
TTrainController::MRSLow
bool MRSLow
Definition: TrainUnit.h:756
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
map of active track element names
Definition: TrackUnit.h:790
TTrain::Crashed
bool Crashed
Definition: TrainUnit.h:442
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:148
TInterface::ScreenRightButton
TBitBtn * ScreenRightButton
Definition: InterfaceUnit.h:255
TTrain::HeadCodePosition
Graphics::TBitmap * HeadCodePosition[4]
Set from the HeadCodeGrPtr[4] pointer values, HeadCodePosition[0] is always the front,...
Definition: TrainUnit.h:456
TInterface::OAListBox
TListBox * OAListBox
Operator action list, sits inside OperatorActionPanel and lists trains in ascending order of time to ...
Definition: InterfaceUnit.h:414
TTrain::TrainID
int TrainID
the train's identification number
Definition: TrainUnit.h:340
TInterface::SaveTTButton
TButton * SaveTTButton
Definition: InterfaceUnit.h:151
TUtilities::CheckStringDouble
bool CheckStringDouble(AnsiString &DoubleString)
checks the string represents a valid double value, returns true for success. Added at v2....
Definition: Utilities.cpp:370
TRailGraphics::bmLightBlueRect
Graphics::TBitmap * bmLightBlueRect
Definition: GraphicUnit.h:523
TInterface::NonSigRouteStartMarker
TGraphicElement * NonSigRouteStartMarker
Definition: InterfaceUnit.h:1168
clB3G3R3
#define clB3G3R3
Definition: GraphicUnit.h:186
TTrainController::TrainVectorAt
TTrain & TrainVectorAt(int Caller, int VecPos)
Return a reference to the train at position VecPos in the TrainVector, carries out range checking on ...
Definition: TrainUnit.cpp:15317
TInterface::EditMenuClick
void __fastcall EditMenuClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9538
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:138
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:12217
TInterface::ModeMenu
TMenuItem * ModeMenu
Definition: InterfaceUnit.h:427
TInterface::MTBFEditBoxClick
void __fastcall MTBFEditBoxClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13884
TInterface::TEVPtr
TTEVPtr TEVPtr
Definition: InterfaceUnit.h:1192
TInterface::MasterClock
TTimer * MasterClock
the program clock (not the timetable clock)
Definition: InterfaceUnit.h:507
TInterface::OutputLog6MouseDown
void __fastcall OutputLog6MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12722
TRailGraphics::SpeedBut70GrndBlackGlyph
Graphics::TBitmap * SpeedBut70GrndBlackGlyph
Definition: GraphicUnit.h:1056
TTrainController::NumFailures
int NumFailures
Definition: TrainUnit.h:798
TInterface::CreateEditTTTitle
AnsiString CreateEditTTTitle
the title of the timetable currently being edited - i.e. the filename without the '....
Definition: InterfaceUnit.h:931
TInterface::AboutMenuItemClick
void __fastcall AboutMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12772
TInterface::SelectStartPair
THVPair SelectStartPair
'Select' menu items
Definition: InterfaceUnit.h:1170
TTrainController::TOpTimeToActMultiMapIterator
TOpTimeToActMultiMap::iterator TOpTimeToActMultiMapIterator
Definition: TrainUnit.h:734
TTrack
Definition: TrackUnit.h:562
TInterface::OperatorActionPanelStartDrag
void __fastcall OperatorActionPanelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:5927
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:862
TInterface::OperateRailwayMenuItem
TMenuItem * OperateRailwayMenuItem
Definition: InterfaceUnit.h:432
TInterface::SaveRailwayTBPButton
TBitBtn * SaveRailwayTBPButton
Save button on TrackBuildPanel.
Definition: InterfaceUnit.h:79
TTrain::ExitSpeedFull
double ExitSpeedFull
speed when leaving the next element
Definition: TrainUnit.h:391
TInterface::MTBFLabel
TLabel * MTBFLabel
Definition: InterfaceUnit.h:490
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1380
TInterface::SelectBitmap
Graphics::TBitmap * SelectBitmap
the graphic defined by Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1093
TInterface::PreventGapOffsetResetting
bool PreventGapOffsetResetting
during gap setting gaps are highlighted in turn for the user to select the matching gap,...
Definition: InterfaceUnit.h:1004
TInterface::TakeSignallerControlMenuItem
TMenuItem * TakeSignallerControlMenuItem
Definition: InterfaceUnit.h:469
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TInterface::Pasting
@ Pasting
Definition: InterfaceUnit.h:904
TInterface::AddTextButton
TBitBtn * AddTextButton
Definition: InterfaceUnit.h:72
TInterface::LoadRailwayMenuItem
TMenuItem * LoadRailwayMenuItem
Definition: InterfaceUnit.h:418
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TInterface::CrashImage
TImage * CrashImage
Definition: InterfaceUnit.h:271
TTrainController::RandomFailureCounter
unsigned int RandomFailureCounter
new at v2.4.0, resets after 53 seconds (53 prime so can trigger at any clock time)
Definition: TrainUnit.h:814
TInterface::USERGRAPHICS_DIR_NAME
static const UnicodeString USERGRAPHICS_DIR_NAME
Definition: InterfaceUnit.h:888
TInterface::mbLeftDown
bool mbLeftDown
true when the left mouse button is down
Definition: InterfaceUnit.h:986
TTrainController::TwoLocationList
TServiceCallingLocsList TwoLocationList
Definition: TrainUnit.h:808
TInterface::ProgramVersion
UnicodeString ProgramVersion
Definition: InterfaceUnit.h:874
TInterface::TTClockResetButton
TButton * TTClockResetButton
Definition: InterfaceUnit.h:225
TUtilities::CheckAndReadFileInt
bool CheckAndReadFileInt(std::ifstream &InFile, int Lowest, int Highest, int &OutInt)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success ...
Definition: Utilities.cpp:280
TInterface::TempCursor
TCursor TempCursor
stores the screen cursor while a temporary cursor (ususlly an hourglass) is displayed
Definition: InterfaceUnit.h:1157
TDisplay::HideWarningLog
void HideWarningLog(int Caller)
Hide all the warnings from the top part of the screen - for timetable clock adjustment.
Definition: DisplayUnit.cpp:549
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:129
TUtilities::DecimalPoint
char DecimalPoint
added at v2.4.0 so can use the local value in loaded session files
Definition: Utilities.h:45
TInterface::ConstructPrefDir
TOnePrefDir * ConstructPrefDir
the Pref Dir under construction
Definition: InterfaceUnit.h:1177
TInterface::SigsOnLeftImage1
TImage * SigsOnLeftImage1
Definition: InterfaceUnit.h:288
TInterface::BuildTrackMenuItemClick
void __fastcall BuildTrackMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:912
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2956
TInterface::ClearandRebuildRailway
void ClearandRebuildRailway(int Caller)
Clear screen and rebuild it from stored data, uses HiddenScreen to avoid flicker.
Definition: InterfaceUnit.cpp:14127
TInterface::DisplayOneTTLineInPanel
void DisplayOneTTLineInPanel(int Caller, AnsiString Data, bool ServiceEntry)
Display a line from the TimetableEditVector (consists of a series of AnsiStrings, each of which repre...
Definition: InterfaceUnit.cpp:5598
TInterface::PlanPrefDirsMenuItem
TMenuItem * PlanPrefDirsMenuItem
Definition: InterfaceUnit.h:429
TInterface::AreAnyTimesInCurrentEntry
bool AreAnyTimesInCurrentEntry()
Search the timetable entry pointed to by TTCurrentEntryPtr and if any times (HH:MM) are present retur...
Definition: InterfaceUnit.cpp:5690
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:8751
TInterface::AutoRouteStartMarker
TGraphicElement * AutoRouteStartMarker
Definition: InterfaceUnit.h:1168
TInterface::RestoreTTButtonClick
void __fastcall RestoreTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4654
TInterface::SaveTTButtonClick
void __fastcall SaveTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4267
TInterface::FormCreate
void __fastcall FormCreate(TObject *Sender)
Definition: InterfaceUnit.cpp:805
TGraphicElement::SetSourceRect
void SetSourceRect(int Left, int Top)
Set SourceRect member values from those supplied and existing Width & Height - ensure this is only ca...
Definition: TrackUnit.h:472
TTrack::SelectPush
void SelectPush(TTrackElement TrackElement)
Store a TrackElement in the SelectVector.
Definition: TrackUnit.h:933
TAllRoutes::SignallerRemovedTrainAutoRoute
TOneRoute SignallerRemovedTrainAutoRoute
if train was on an AutoSigsRoute when removed then this stores the route so that signals can be reset
Definition: TrackUnit.h:1704
TTrainController::MassHigh
bool MassHigh
Definition: TrainUnit.h:756
TInterface::TimetablePanel
TPanel * TimetablePanel
'Create a timetable'/'Edit a timetable' panel that contains the topmost buttons (show/hide & exit)
Definition: InterfaceUnit.h:369
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2091
TTrain::PlotTrainWithNewBackgroundColour
void PlotTrainWithNewBackgroundColour(int Caller, TColor NewBackgroundColour, TDisplay *Disp)
Changes the train's background colour (e.g. to pale green if stopped at a station) Note that this use...
Definition: TrainUnit.cpp:3397
TInterface::LoadSessionMenuItem
TMenuItem * LoadSessionMenuItem
Definition: InterfaceUnit.h:422
TInterface::SpeedButton69
TSpeedButton * SpeedButton69
Definition: InterfaceUnit.h:581
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:135
TInterface::OutputLog5MouseDown
void __fastcall OutputLog5MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12713
TInterface::ErrorButton
TBitBtn * ErrorButton
the 'Press to exit' button on the error screen
Definition: InterfaceUnit.h:263
TInterface::WarningFlash
bool WarningFlash
toggles on and off automatically at a cycle of about 0.5 sec, used to drive the warning icons during ...
Definition: InterfaceUnit.h:1052
TInterface::CurrentSpeedButton
TSpeedButton * CurrentSpeedButton
stores the selected track build element button during railway building
Definition: InterfaceUnit.h:1189
TInterface::MainScreenMouseDown
void __fastcall MainScreenMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:5948
TTrain::ExitTimeFull
TDateTime ExitTimeFull
times used in SetTrainMovementValues corresponding to the next element the train runs on
Definition: TrainUnit.h:424
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:159
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:798
TInterface::TotalTicks
unsigned int TotalTicks
total clock ticks
Definition: InterfaceUnit.h:1099
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2557
TInterface::SpeedTopLabel2
TLabel * SpeedTopLabel2
Definition: InterfaceUnit.h:117
TInterface::MMoveTextGraphicTextFoundFlag
bool MMoveTextGraphicTextFoundFlag
Definition: InterfaceUnit.h:991
SignallerChangeDirection
@ SignallerChangeDirection
Definition: TrainUnit.h:52
TRailGraphics::GridBitmap
Graphics::TBitmap * GridBitmap
Definition: GraphicUnit.h:901
TInterface::PowerBottomLabel
TLabel * PowerBottomLabel
Definition: InterfaceUnit.h:195
TInterface::PasteMenuItem
TMenuItem * PasteMenuItem
Definition: InterfaceUnit.h:445
TTextHandler::EnterAndDisplayNewText
void EnterAndDisplayNewText(int Caller, TTextItem Text, int HPos, int VPos)
add Text to TextVector and display it on the screen
Definition: TextUnit.cpp:190
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:12005
TInterface::CreateEditTTFileName
AnsiString CreateEditTTFileName
the full path and filename of the timetable file
Definition: InterfaceUnit.h:929
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:12783
TTrainController::TotLateExitMins
float TotLateExitMins
Definition: TrainUnit.h:775
TInterface::ManualLCDownAttentionWarning
bool ManualLCDownAttentionWarning
Displays the manual LC down warning graphic in the panel on the LHS of the railway when there are no ...
Definition: InterfaceUnit.h:1243
TInterface::PerformanceLogButtonClick
void __fastcall PerformanceLogButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2380
TTrainController::CheckSessionContinuationAutoSigEntries
bool CheckSessionContinuationAutoSigEntries(int Caller, std::ifstream &SessionFile)
Part of the session file integrity check for ContinuationAutoSigEntries, true for success.
Definition: TrainUnit.cpp:15163
IDInt
Definition: TrackUnit.h:511
TInterface::SelectLengthsMenuItemClick
void __fastcall SelectLengthsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10676
TInterface::NewSelectBitmapHLoc
int NewSelectBitmapHLoc
the new (during & at end of moving) HLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1107
TInterface::LoadUserGraphic
void LoadUserGraphic(int Caller)
Load a user-defined graphic (bmp, gif, jpg, png).
Definition: InterfaceUnit.cpp:21110
TInterface::TTCurrentEntryPtr
TTEVPtr TTCurrentEntryPtr
Definition: InterfaceUnit.h:1192
TRunningEntry
TRunningEntry
contains status info for each train
Definition: TrainUnit.h:85
TInterface::OutputLog6
TLabel * OutputLog6
Definition: InterfaceUnit.h:305
TUtilities
Definition: Utilities.h:36
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4404
TInterface::CreateTimetableMenuItemClick
void __fastcall CreateTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3284
TInterface::ExportTTButtonClick
void __fastcall ExportTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4736
TDisplay
Definition: DisplayUnit.h:48
TInterface::TTClockxEighthButtonClick
void __fastcall TTClockxEighthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13454
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:10103
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:146
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:816
TInterface::Text_X
int Text_X
the 'X' pixel value for an item of text
Definition: InterfaceUnit.h:1141
TInterface::SpeedVariableLabel
TLabel * SpeedVariableLabel
Definition: InterfaceUnit.h:188
TInterface::SigPrefNonConsecButton
TBitBtn * SigPrefNonConsecButton
Definition: InterfaceUnit.h:662
TTrain::StoppedWithoutPower
bool StoppedWithoutPower
Definition: TrainUnit.h:443
TInterface::GetTrainStatusFloat
AnsiString GetTrainStatusFloat(int Caller, int TrainID, AnsiString FormatNoDPStr, AnsiString SpecialStr)
used for floating window to display train status
Definition: InterfaceUnit.cpp:16829
TInterface::PowerVariableLabel
TLabel * PowerVariableLabel
Definition: InterfaceUnit.h:196
TActionEventType
TActionEventType
Used for reporting error conditions & warnings.
Definition: TrainUnit.h:39
TInterface::GapsNotSetImage
TImage * GapsNotSetImage
Definition: InterfaceUnit.h:285
TInterface::Level1Mode
enum TInterface::TLevel1Mode Level1Mode
TInterface::CallLogTickerLabel
TLabel * CallLogTickerLabel
diagnostic label displaying the call log depth, made visible by ctrl+ alt+ 2
Definition: InterfaceUnit.h:327
TInterface::TimetableEditVector
TTimetableEditVector TimetableEditVector
Definition: InterfaceUnit.h:1195
TTrainController::TrainExistsAtIdent
bool TrainExistsAtIdent(int Caller, int TrainID)
new at v2.4.0 return true if find the train (added at v2.4.0 as can select a removed train in OAListB...
Definition: TrainUnit.cpp:9457
SignallerJoin
@ SignallerJoin
Definition: TrainUnit.h:51
TTrain::StepForwardFlag
bool StepForwardFlag
set when the signaller command to step forward one element has been given
Definition: TrainUnit.h:375
TInterface::SaveRailwayDialog
TSaveDialog * SaveRailwayDialog
Definition: InterfaceUnit.h:502
TInterface::TTClockAdjustWarningPanel
TPanel * TTClockAdjustWarningPanel
Definition: InterfaceUnit.h:219
TTrainController::TotEarlyExitMins
float TotEarlyExitMins
Definition: TrainUnit.h:771
TInterface::TrainTTInfoOnOffMenuItemClick
void __fastcall TrainTTInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5809
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:98
TTrainController::Operate
void Operate(int Caller)
called every clock tick to introduce new trains and update existing trains
Definition: TrainUnit.cpp:8765
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:154
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:887
TTrain::PowerAtRail
double PowerAtRail
in Watts (taken as 80% of the train's Gross Power, i.e. that entered by the user)
Definition: TrainUnit.h:406
TOnePrefDir::FindLinkingPrefDir
bool FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that links to another element at given vector number and link number & posit...
Definition: TrackUnit.cpp:13093
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:776
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:14114
TAllRoutes::LevelCrossingBarrierDownDelay
const float LevelCrossingBarrierDownDelay
the full value in seconds for which the level crossing flashes prior to opening to trains
Definition: TrackUnit.h:1692
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1685
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:162
TInterface::SetSaveMenuAndButtons
void SetSaveMenuAndButtons(int Caller)
Called during the ClockTimer2 function to set screen boundaries, buttons & menu items.
Definition: InterfaceUnit.cpp:17384
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TInterface::TIMETABLE_DIR_NAME
static const UnicodeString TIMETABLE_DIR_NAME
Definition: InterfaceUnit.h:883
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:131
TInterface::SaveImageAndPrefDirsMenuItem
TMenuItem * SaveImageAndPrefDirsMenuItem
Definition: InterfaceUnit.h:462
TInterface::LoadRailwayMenuItemClick
void __fastcall LoadRailwayMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2466
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7603
TInterface::FormKeyUp
void __fastcall FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:12661
TInterface::CopyTTEntryKeyFlag
bool CopyTTEntryKeyFlag
Definition: InterfaceUnit.h:1067
TTrainDataEntry::TrainOperatingDataVector
TTrainOperatingDataVector TrainOperatingDataVector
operating information for the train including all its repeats
Definition: TrainUnit.h:206
TInterface::OutputLog9MouseDown
void __fastcall OutputLog9MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12752
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:646
TInterface::RecoverClipboardMessageSent
bool RecoverClipboardMessageSent
indicates that the warning about pasting at top left in a new application has been given,...
Definition: InterfaceUnit.h:1006
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:148
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:897
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1503
TTrain::IsThereAnAdjacentTrain
bool IsThereAnAdjacentTrain(int Caller, TTrain *&TrainToBeJoinedBy)
Definition: TrainUnit.cpp:4984
TInterface::ApproachLocking
void ApproachLocking(int Caller, TDateTime Now)
Function that deals with approach locking during ClockTimer2 function.
Definition: InterfaceUnit.cpp:16175
TInterface::TimetableTitle
AnsiString TimetableTitle
the titles of the loaded railway and loaded timetable, i.e. the filenames without the extension
Definition: InterfaceUnit.h:943
TInterface::BlackBgndMenuItemClick
void __fastcall BlackBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12816
TInterface::Deleting
@ Deleting
Definition: InterfaceUnit.h:904
TInterface::RestoreAllDefaultLengthsButton
TBitBtn * RestoreAllDefaultLengthsButton
Definition: InterfaceUnit.h:83
TInterface::ClearAllMenuItemClick
void __fastcall ClearAllMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3210
TUtilities::EventLog
std::deque< AnsiString > EventLog
event store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:57
TPrefDirElement::SetXLink
void SetXLink(int input)
Used in pasting pref dirs.
Definition: TrackUnit.h:364
TInterface::MoveTTEntryUpKeyFlag
bool MoveTTEntryUpKeyFlag
Definition: InterfaceUnit.h:1065
TActionVectorEntry::FormatType
TTimetableFormatType FormatType
defines the timetable action type
Definition: TrainUnit.h:119
TInterface::TextBox
TEdit * TextBox
the edit box that accepts text to be added
Definition: InterfaceUnit.h:94
TGraphicElement::GetHPos
int GetHPos()
Definition: TrackUnit.h:461
TOnePrefDir::SearchVectorSize
unsigned int SearchVectorSize() const
Return the vector size.
Definition: TrackUnit.h:1392
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:657
TTrainController::TimetableStartTime
TDateTime TimetableStartTime
the start time of the current timetable
Definition: TrainUnit.h:655
TTrainController::UnplotTrains
void UnplotTrains(int Caller)
unplot all trains from screen
Definition: TrainUnit.cpp:9109
TInterface::ScreenGridFlag
bool ScreenGridFlag
true when the screen grid is displayed
Definition: InterfaceUnit.h:1014
TInterface::InfoCaptionStore
AnsiString InfoCaptionStore
temporary store for the information panel caption
Definition: InterfaceUnit.h:937
TRailGraphics::smBrightGreen
Graphics::TBitmap * smBrightGreen
Definition: GraphicUnit.h:878
TInterface::CopiedEntryFlag
bool CopiedEntryFlag
true when CopiedEntryStr holds a timetable entry in the timetable editor
Definition: InterfaceUnit.h:964
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:15301
TTrainController::EarlyArrivals
int EarlyArrivals
Definition: TrainUnit.h:780
TPrefDirElement::SetEXNumber
void SetEXNumber(int input)
Used in pasting pref dirs.
Definition: TrackUnit.h:376
TInterface::AnyTTKeyFlagSet
bool AnyTTKeyFlagSet()
Definition: InterfaceUnit.h:1205
TTrainController::CreateFormattedTimetable
void CreateFormattedTimetable(int Caller, AnsiString RailwayTitle, AnsiString TimetableTitle, AnsiString CurDir)
Examines the internal timetable (TrainDataVector) and creates from it a chronological (....
Definition: TrainUnit.cpp:15330
TInterface::SetTopIndex
void SetTopIndex(int Caller)
This used in timetable functions when shift keys pressed to make sure that the highlighted entry rema...
Definition: InterfaceUnit.cpp:14105
TTrack::RouteFlashFlag
bool RouteFlashFlag
true while a route is flashing prior to being set
Definition: TrackUnit.h:765
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:13416
TInterface::PowerToggleButtonClick
void __fastcall PowerToggleButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13004
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1297
TOnePrefDir::BiDirectionalPrefDir
bool BiDirectionalPrefDir(int Caller, TPrefDir4MultiMapIterator PDPtr)
Determines whether the preferred direction pointed to has another pref dir in the opposite direction ...
Definition: TrackUnit.cpp:13191
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:152
Points
@ Points
Definition: TrackUnit.h:67
TTrainController::TotLatePassMins
float TotLatePassMins
Definition: TrainUnit.h:774
TTrainController::StripSpaces
void StripSpaces(int Caller, AnsiString &Input)
Strip both leading and trailing spaces at ends of Input and spaces before and after all commas and se...
Definition: TrainUnit.cpp:13645
TInterface::Delay
void Delay(int Caller, double Msec)
Delays operation for the set time in milliseconds.
Definition: InterfaceUnit.cpp:14519
TTrain::JoinedOtherTrainFlag
bool JoinedOtherTrainFlag
true when the train has joined another train following an 'Fjo' timetable command or a signaller join...
Definition: TrainUnit.h:361
TTrainController::OpActionPanelHintDelayCounter
unsigned int OpActionPanelHintDelayCounter
new v2.2.0 on start operation delays the op action panel headcode display for about 3 secs while hint...
Definition: TrainUnit.h:812
TTrainController::BFLow
bool BFLow
Definition: TrainUnit.h:756
TInterface::OutputLog7
TLabel * OutputLog7
Definition: InterfaceUnit.h:306
TTrainController::TotArrDepPass
int TotArrDepPass
Definition: TrainUnit.h:796
TInterface::LastNonCtrlOrShiftKeyDown
int LastNonCtrlOrShiftKeyDown
value of last key (other than Ctrl or Shift) pressed down - to prevent repeated FormKeyDown calls fro...
Definition: InterfaceUnit.h:1105
TTrack::WriteOperatingTrackAndTextToImage
void WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track & text to the image file in their ope...
Definition: TrackUnit.cpp:4139
SignallerPassRedSignal
@ SignallerPassRedSignal
Definition: TrainUnit.h:52
TRailGraphics::ChangeForegroundColour
void ChangeForegroundColour(int Caller, Graphics::TBitmap *BitmapIn, Graphics::TBitmap *BitmapOut, TColor NewForegroundColour, TColor BackgroundColour)
Definition: GraphicUnit.cpp:3362
TInterface::TextItem
int TextItem
used to store a single item of text
Definition: InterfaceUnit.h:1147
TInterface::UserGraphicButtonClick
void __fastcall UserGraphicButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13906
TInterface::OriginalTimetableEditVector
TTimetableEditVector OriginalTimetableEditVector
the complete timetable as a list of AnsiStrings for use in edit timetable functions
Definition: InterfaceUnit.h:1195
TInterface::PresetAutoSigRoutesButtonClick
void __fastcall PresetAutoSigRoutesButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13610
TInterface::SigPrefNonConsecButtonClick
void __fastcall SigPrefNonConsecButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2273
TRailGraphics::SpeedBut68GrndBlackGlyph
Graphics::TBitmap * SpeedBut68GrndBlackGlyph
Definition: GraphicUnit.h:1054
TTrain::SignallerRemoved
bool SignallerRemoved
set when removed under signaller control to force a removal from the display at the next clock tick
Definition: TrainUnit.h:369
TTrain::FrontCodePtr
Graphics::TBitmap * FrontCodePtr
points to the front headcode segment, this is set to red or blue depending on TrainMode
Definition: TrainUnit.h:460
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all points appropriately. Also called when a new train is added at...
Definition: TrackUnit.cpp:16717
TInterface::MMovePrefDirSelFlag
bool MMovePrefDirSelFlag
Definition: InterfaceUnit.h:989
TInterface::TwoLocationNamePanel
TPanel * TwoLocationNamePanel
Definition: InterfaceUnit.h:663
Continuation
@ Continuation
Definition: TrackUnit.h:67
TInterface::ScreenUpButton
TBitBtn * ScreenUpButton
Definition: InterfaceUnit.h:257
TInterface::TTServiceSyntaxCheckButton
TButton * TTServiceSyntaxCheckButton
Definition: InterfaceUnit.h:149
TTrainController::CallOnWarning
bool CallOnWarning
Definition: TrainUnit.h:742
TInterface::SetLengthsButton
TBitBtn * SetLengthsButton
Definition: InterfaceUnit.h:77
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
GraphicUnit.h
TInterface::AppActivate
void __fastcall AppActivate(TObject *Sender)
Definition: InterfaceUnit.cpp:860
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: InterfaceUnit.h:49
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3719
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:5920
TInterface::AddTextButtonClick
void __fastcall AddTextButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1134
TInterface::MMoveTrackSelFlag
bool MMoveTrackSelFlag
Definition: InterfaceUnit.h:988
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:86
TInterface::ReselectMenuItemClick
void __fastcall ReselectMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9586
TInterface::SaveTTAsKeyFlag
bool SaveTTAsKeyFlag
Definition: InterfaceUnit.h:1076
TInterface::SaveTTEntryButtonClick
void __fastcall SaveTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4117
TInterface::TimetablePanelLabel
TLabel * TimetablePanelLabel
label to the left of TimetablePanel
Definition: InterfaceUnit.h:321
TTrack::PointFlashFlag
bool PointFlashFlag
true when points are flashing during manual change
Definition: TrackUnit.h:763
TTrainController::OnTimeDeps
int OnTimeDeps
Definition: TrainUnit.h:790
TTrain::RestoreTimetableLocation
AnsiString RestoreTimetableLocation
stores the location name at which signaller control is taken, to ensure that it is back at that locat...
Definition: TrainUnit.h:434
TTrainController::TimetableIntegrityCheck
bool TimetableIntegrityCheck(int Caller, char *FileName, bool GiveMessages, bool CheckLocationsExistInRailway)
Checks overall timetable integrity, calls many other specific checking functions, returns true for su...
Definition: TrainUnit.cpp:9811
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TDisplay::Left
int Left()
Return the left pixel position of the screen.
Definition: DisplayUnit.h:114
TTrain::SignallerMaxSpeed
int SignallerMaxSpeed
maximum train speed under signaller control (in km/h)
Definition: TrainUnit.h:333
TInterface::BufferAttentionImage
TImage * BufferAttentionImage
Definition: InterfaceUnit.h:268
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:12048
TTrainController::SendPerformanceSummary
void SendPerformanceSummary(int Caller, std::ofstream &PerfFile)
At the end of operation a summary of overall performance is sent to the performance file by this func...
Definition: TrainUnit.cpp:18784
TInterface::OperatorActionButtonClick
void __fastcall OperatorActionButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13718
TInterface::SpeedEditBox
TEdit * SpeedEditBox
Definition: InterfaceUnit.h:185
TInterface::LoadRailwayDialog
TOpenDialog * LoadRailwayDialog
Definition: InterfaceUnit.h:496
TInterface::CopyMenuItem
TMenuItem * CopyMenuItem
Definition: InterfaceUnit.h:441
TInterface::ResetDefaultLengthButtonClick
void __fastcall ResetDefaultLengthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1691
RepairFailedTrain
@ RepairFailedTrain
Definition: TrainUnit.h:52
TInterface::NoOperMode
@ NoOperMode
Definition: InterfaceUnit.h:893
TInterface::ErrorLogCalledFlag
bool ErrorLogCalledFlag
true when an error has been thrown, stops repeated calls to ErrorLog and stops the MasterClockTimer f...
Definition: InterfaceUnit.h:974
TInterface::NextTTEntryKeyFlag
bool NextTTEntryKeyFlag
Definition: InterfaceUnit.h:1064
TInterface::RouteFlashStartTime
TDateTime RouteFlashStartTime
stores the starting time (timetable clock time) for route flashing
Definition: InterfaceUnit.h:1164
TInterface::PerformancePanelLabel
TLabel * PerformancePanelLabel
label at the top of PerformancePanel
Definition: InterfaceUnit.h:311
TInterface::BlueBgndMenuItemClick
void __fastcall BlueBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12868
TInterface::SetTrackLengths
void SetTrackLengths(int Caller, int Distance, int SpeedLimit)
Called during track building when setting distances, to calculate and set the individual track elemen...
Definition: InterfaceUnit.cpp:20459
TInterface::SpeedToggleButtonClick
void __fastcall SpeedToggleButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12894
TTrainController::ContinuationEntryFloatingTTString
AnsiString ContinuationEntryFloatingTTString(int Caller, TTrainDataEntry *TTDEPtr, int RepeatNumber, int IncrementalMinutes, int IncrementalDigits)
Build string for use in floating window for expected trains at continuations.
Definition: TrainUnit.cpp:9488
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3336
TGraphicElement::GetVPos
int GetVPos()
Definition: TrackUnit.h:466
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1520
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:89
TTrain::SPADFlag
bool SPADFlag
set when running past a red signal without permission flags to indicate relevant stop conditions or p...
Definition: TrainUnit.h:440
TInterface::HomeButtonClick
void __fastcall HomeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9467
TInterface::PointFlashStartTime
TDateTime PointFlashStartTime
stores the starting time (timetable clock time) for points flashing
Definition: InterfaceUnit.h:1162
TInterface::RailwayWebSiteMenuItemClick
void __fastcall RailwayWebSiteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12808
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:624
TInterface::TTFirstServicePtr
TTEVPtr TTFirstServicePtr
Definition: InterfaceUnit.h:1192
TInterface::ClockTimer2
void ClockTimer2(int Caller)
The main loop, called every clock tick via MasterClockTimer.
Definition: InterfaceUnit.cpp:8390
TDisplay::PlotDashedRect
void PlotDashedRect(int Caller, TRect Rect)
Plot a dashed rectangle for the area defined by Rect, used when selecting display areas.
Definition: DisplayUnit.cpp:499
TInterface::NewTTEntryButtonClick
void __fastcall NewTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3681
TInterface::LoadSessionMenuItemClick
void __fastcall LoadSessionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3196
TTrack::SelectVectorClear
void SelectVectorClear()
Definition: TrackUnit.h:938
TInterface::PerformanceFileName
AnsiString PerformanceFileName
full path and filename of the performance file
Definition: InterfaceUnit.h:941
TInterface::AutoSigsButton
TBitBtn * AutoSigsButton
Definition: InterfaceUnit.h:201
TInterface::PopupMenu
TPopupMenu * PopupMenu
Definition: InterfaceUnit.h:493
TTrainController::OnTimeExits
int OnTimeExits
Definition: TrainUnit.h:792
TInterface::LoadSessionFlag
bool LoadSessionFlag
true when a session load command has been given - implemented at next clock tick
Definition: InterfaceUnit.h:984
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:281
TInterface::NoTrackMode
@ NoTrackMode
Definition: InterfaceUnit.h:903
TInterface::TimetableValidFlag
bool TimetableValidFlag
indicates that a 'Validate timetable' button click in the timetable editor has succeeded
Definition: InterfaceUnit.h:1044
TInterface::CancelSelectionFlag
bool CancelSelectionFlag
used in case pasting to avoid RecoverClipboard call when set
Definition: InterfaceUnit.h:958
TInterface::TimetableControlMenuItem
TMenuItem * TimetableControlMenuItem
Definition: InterfaceUnit.h:470
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:331
TUtilities::PerformanceFile
std::ofstream PerformanceFile
the file where the performance log for a particular period of operation is saved
Definition: Utilities.h:53
TInterface::PreferredRoute
bool PreferredRoute
true when AutoSig or preferred route building selected during operation (always same state as ConsecS...
Definition: InterfaceUnit.h:1000
TInterface::ConvertCRLFsToCommas
void ConvertCRLFsToCommas(int Caller, AnsiString &ConvStr)
Used in timetable editing functions to convert any CRLFs in intended service entries to commas.
Definition: InterfaceUnit.cpp:5372
TInterface::OutputLog2MouseDown
void __fastcall OutputLog2MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12684
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:84
TTrackElement::TempTrackMarker01
bool TempTrackMarker01
Definition: TrackUnit.h:140
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TInterface::LoadTimetableFromSessionFile
bool LoadTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
Loads timetable into memory from a session file, true if successful.
Definition: InterfaceUnit.cpp:18983
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:782
TUtilities::DateTimeStamp
AnsiString DateTimeStamp()
creates a string of the form 'dd/mm/yyyy hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:67
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:891
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4657
TInterface::AllEntriesTTListBoxMouseUp
void __fastcall AllEntriesTTListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:4935
TInterface::TwoLocationNameCheckBox
TCheckBox * TwoLocationNameCheckBox
Definition: InterfaceUnit.h:666
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1712
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:8527
TInterface::FontButton
TBitBtn * FontButton
Definition: InterfaceUnit.h:75
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:123
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:802
TInterface::NextTTEntryButtonClick
void __fastcall NextTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3599
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:209
TInterface::~TInterface
__fastcall ~TInterface()
destructor
Definition: InterfaceUnit.cpp:744
TInterface::CancelTTEntryButtonClick
void __fastcall CancelTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4617
TInterface::TTEVPtr
std::vector< AnsiString >::iterator TTEVPtr
typedef for pointers to entries in edit timetable functions
Definition: InterfaceUnit.h:915
TInterface::SaveHeaderMenu1Click
void __fastcall SaveHeaderMenu1Click(TObject *Sender)
Definition: InterfaceUnit.cpp:3136
TInterface::TTStartTimePtr
TTEVPtr TTStartTimePtr
Definition: InterfaceUnit.h:1192
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:720
TInterface::TTClockAdjPanel
TPanel * TTClockAdjPanel
Definition: InterfaceUnit.h:218
TInterface::BuildTrainDataVectorForLoadFile
bool BuildTrainDataVectorForLoadFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway, bool SessionFile)
Convert a stored timetable file (either as a stand alone file or within a session file) to a loaded t...
Definition: InterfaceUnit.cpp:19204
TInterface::ConflictPanel
TPanel * ConflictPanel
Definition: InterfaceUnit.h:242
TInterface::CompileAllEntriesMemoAndSetPointers
void CompileAllEntriesMemoAndSetPointers(int Caller)
Used during timetable editing funtions to compile the list of entries into the left hand long entry w...
Definition: InterfaceUnit.cpp:5120
TInterface::CopiedEntryStr
AnsiString CopiedEntryStr
a timetable entry that has been copied
Definition: InterfaceUnit.h:927
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:18972
TInterface::SelectMenuItem
TMenuItem * SelectMenuItem
Definition: InterfaceUnit.h:438
TInterface::MoveTTEntryDownKeyFlag
bool MoveTTEntryDownKeyFlag
Definition: InterfaceUnit.h:1066
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1840
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4642
Connection
@ Connection
Definition: TrackUnit.h:77
TInterface::TTTextButtonClick
void __fastcall TTTextButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4775
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3696
TTrainController::TrainFailedWarning
bool TrainFailedWarning
Flags to enable the relevant warning graphics to flash at the left hand side of the screen.
Definition: TrainUnit.h:742
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1687
TInterface::LengthOKButton
TBitBtn * LengthOKButton
distance/speed setting buttons - left to right & top to bottom
Definition: InterfaceUnit.h:86
TTrain::NextTrainID
static int NextTrainID
the ID value to be used for the next train that is created, static so that it doesn't need an object ...
Definition: TrainUnit.h:297
TInterface::PreviousTTEntryButtonClick
void __fastcall PreviousTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3640
TInterface::UserGraphicButton
TBitBtn * UserGraphicButton
Definition: InterfaceUnit.h:88
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:16530
TInterface::Text_Y
int Text_Y
as above for 'Y'
Definition: InterfaceUnit.h:1143
TInterface::MMoveCopyCutSelPickedUpFlag
bool MMoveCopyCutSelPickedUpFlag
Definition: InterfaceUnit.h:990
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:18244
TInterface::DeleteTTEntryButton
TButton * DeleteTTEntryButton
Definition: InterfaceUnit.h:139
DefaultTrackSpeedLimit
#define DefaultTrackSpeedLimit
Definition: TrackUnit.h:38
TInterface::ReselectUserGraphicClick
void __fastcall ReselectUserGraphicClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13939
TInterface::TTClockAdd1mButtonClick
void __fastcall TTClockAdd1mButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13533
TInterface::SubMinsButton
TButton * SubMinsButton
Definition: InterfaceUnit.h:148
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:6964
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:541
TInterface::ValidateTimetableButtonClick
void __fastcall ValidateTimetableButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4434
TInterface::UserGraphicMoveVPos
int UserGraphicMoveVPos
used to store the original user graphic 'H' & 'V' positions for use during moving
Definition: InterfaceUnit.h:1153
TActionVectorEntry::LocationName
AnsiString LocationName
Definition: TrainUnit.h:103
TInterface::LoadTimetableMenuItem
TMenuItem * LoadTimetableMenuItem
Definition: InterfaceUnit.h:421
TPrefDirElement::SetTrackVectorPosition
void SetTrackVectorPosition(int TVPos)
Used in pasting pref dirs.
Definition: TrackUnit.h:341
TInterface::LocationNameButtonClick
void __fastcall LocationNameButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1217
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5728
TInterface::SaveMenuItem
TMenuItem * SaveMenuItem
Definition: InterfaceUnit.h:420
TInterface::GapSetting
@ GapSetting
Definition: InterfaceUnit.h:903
TTrain::TimeTimeLocArrived
bool TimeTimeLocArrived
indicates whether has arrived (true) or not when ActionVectorEntryPtr->FormatType == TimeTimeLoc
Definition: TrainUnit.h:304
TInterface::ShowHideTTButton
TBitBtn * ShowHideTTButton
Definition: InterfaceUnit.h:130
TInterface::ScreenDownButton
TBitBtn * ScreenDownButton
Definition: InterfaceUnit.h:258
TTrain::LeadEntryPos
int LeadEntryPos
Definition: TrainUnit.h:337
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:769
TTrainController::LateArrivals
int LateArrivals
Definition: TrainUnit.h:784
TInterface::DeleteOnePrefDirButton
TBitBtn * DeleteOnePrefDirButton
Definition: InterfaceUnit.h:123
TInterface::PauseEntryTTClockSpeed
float PauseEntryTTClockSpeed
rate at which the timetable clock runs on entry to the adjust routine - to restore if cancelled
Definition: InterfaceUnit.h:1084
TTrainController::ReplotTrains
void ReplotTrains(int Caller, TDisplay *Disp)
plot all trains on the display
Definition: TrainUnit.cpp:9079
TInterface::MetreVariableLabel
TLabel * MetreVariableLabel
Definition: InterfaceUnit.h:109
TInterface::AllEntriesTTListBoxTopPosition
int AllEntriesTTListBoxTopPosition
stores the TopIndex property when keys are used to select items in the TT edit panel
Definition: InterfaceUnit.h:1103
TInterface::SigImagePanel
TPanel * SigImagePanel
new at v2.3.0 for handed signals
Definition: InterfaceUnit.h:395
TTrain::FloatingTimetableString
AnsiString FloatingTimetableString(int Caller, TActionVectorEntry *Ptr)
Used in the floating window to display the timetable.
Definition: TrainUnit.cpp:7054
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:747
TInterface::CPGenFileButtonClick
void __fastcall CPGenFileButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14060
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:17470
TInterface::TTClockAdd10mButtonClick
void __fastcall TTClockAdd10mButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13513
TRailGraphics::SpeedBut73GrndBlackGlyph
Graphics::TBitmap * SpeedBut73GrndBlackGlyph
Definition: GraphicUnit.h:1059
TTrain::AValue
double AValue
this is a useful shorthand value in calculating speeds and transit times in SetTrainMovementValues [=...
Definition: TrainUnit.h:383
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7563
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3098
TTrainController::WriteTrainsToImage
void WriteTrainsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click) to write all trains to the image file.
Definition: TrainUnit.cpp:9094
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:133
TInterface::TTClockSpeedLabel
TLabel * TTClockSpeedLabel
Definition: InterfaceUnit.h:337
TTrack::FourAspectBuild
@ FourAspectBuild
Definition: TrackUnit.h:862
TInterface::ManualLCDownImage
TImage * ManualLCDownImage
Definition: InterfaceUnit.h:274
TTrainController::OpTimeToActMultiMapIterator
TOpTimeToActMultiMapIterator OpTimeToActMultiMapIterator
added v2.2.0 for Op time to act display
Definition: TrainUnit.h:822
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:642
TInterface::NewEntryInPreparationFlag
bool NewEntryInPreparationFlag
true when a new timetable entry is being prepared in the timetable editor
Definition: InterfaceUnit.h:994
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:76
TInterface::OAPanelLabel
TLabel * OAPanelLabel
Definition: InterfaceUnit.h:342
TInterface::GetVersion
UnicodeString GetVersion()
determined automatically from the project options 'Version Info'
Definition: InterfaceUnit.cpp:879
TInterface::OneEntryTimetableContents
AnsiString OneEntryTimetableContents
the current text in the large right hand timetable edit window
Definition: InterfaceUnit.h:939
TInterface::SelectRect
TRect SelectRect
the rectangle in HLoc & VLoc terms set in Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1186
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:293
TTrain::ZeroPowerNoJoinedByMessage
bool ZeroPowerNoJoinedByMessage
Definition: TrainUnit.h:313
TInterface::LocationNameComboBox
TComboBox * LocationNameComboBox
the combobox that lists location names
Definition: InterfaceUnit.h:179
TInterface::ValidateTimetableKeyFlag
bool ValidateTimetableKeyFlag
Definition: InterfaceUnit.h:1074
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:767
TInterface::ExitOperationButton
TBitBtn * ExitOperationButton
Definition: InterfaceUnit.h:209
TTrain::CalcTimeToAct
float CalcTimeToAct(int Caller)
new v2.2.0 for operator action panel. Calculates the time left for operator action to avoid unnecessa...
Definition: TrainUnit.cpp:8423
TTrainController::SaveSessionContinuationAutoSigEntries
void SaveSessionContinuationAutoSigEntries(int Caller, std::ofstream &SessionFile)
save ContinuationAutoSigEntries to a session file
Definition: TrainUnit.cpp:15123
TInterface::SignalStopImage
TImage * SignalStopImage
Definition: InterfaceUnit.h:267
TInterface::OutputLog9
TLabel * OutputLog9
Definition: InterfaceUnit.h:308
TInterface::SetCaption
void SetCaption(int Caller)
Sets the railway and timetable titles at the top of the screen.
Definition: InterfaceUnit.cpp:17840
TOnePrefDir::ExternalClearPrefDirAnd4MultiMap
void ExternalClearPrefDirAnd4MultiMap()
Empty the existing preferred direction vector & map - for use by other classes.
Definition: TrackUnit.h:1398
TInterface::SetInitialPrefDirModeEditMenu
void SetInitialPrefDirModeEditMenu()
Enables or disables the initial Edit mode submenu items in PrefDir mode.
Definition: InterfaceUnit.cpp:20841
TInterface::MainScreenMouseMove
void __fastcall MainScreenMouseMove(TObject *Sender, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:7642
TInterface::DistanceContinuing
@ DistanceContinuing
Definition: InterfaceUnit.h:903
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:667
TInterface::CutTTEntryKeyFlag
bool CutTTEntryKeyFlag
Definition: InterfaceUnit.h:1068
TPrefDirElement::SetELinkPos
void SetELinkPos(int input)
Used in pasting pref dirs.
Definition: TrackUnit.h:358
TInterface::SigsOnLeftImage2
TImage * SigsOnLeftImage2
Definition: InterfaceUnit.h:289
TInterface::ChainEdit
TEdit * ChainEdit
Definition: InterfaceUnit.h:105
TInterface::CPAtLocCheckBox
TCheckBox * CPAtLocCheckBox
Definition: InterfaceUnit.h:250
TInterface::PasteTTEntryButtonClick
void __fastcall PasteTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3979
TInterface::TestFunction
void TestFunction()
Called for diagnostic purposes when keys CTRL ALT 4 pressed.
Definition: InterfaceUnit.cpp:20953
TInterface::ExportTTKeyFlag
bool ExportTTKeyFlag
Definition: InterfaceUnit.h:1078
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:11426
TTrain::FirstHalfMove
bool FirstHalfMove
true when the train is on the first half of an element when it displays as fully on two elements....
Definition: TrainUnit.h:359
TInterface::MovingTrainPresentOnFlashingRoute
bool MovingTrainPresentOnFlashingRoute(int Caller)
Examines a flashing route (i.e. one being set) and returns true if a moving train is detected on it a...
Definition: InterfaceUnit.cpp:14555
TInterface::Level2TrackMode
enum TInterface::TLevel2TrackMode Level2TrackMode
TInterface::DeleteTTEntryKeyFlag
bool DeleteTTEntryKeyFlag
Definition: InterfaceUnit.h:1070
TTrainController::LatePasses
int LatePasses
Definition: TrainUnit.h:786
TInterface::SaveRailwayBaseModeButton
TBitBtn * SaveRailwayBaseModeButton
Save button at the top left hand corner of the screen when no mode is selected.
Definition: InterfaceUnit.h:65
TInterface::SelectBiDirPrefDirsMenuItem
TMenuItem * SelectBiDirPrefDirsMenuItem
Definition: InterfaceUnit.h:448
TInterface::UserGraphicReselectPanel
TPanel * UserGraphicReselectPanel
Definition: InterfaceUnit.h:491
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:101
TInterface::RotLeftMenuItem
TMenuItem * RotLeftMenuItem
Definition: InterfaceUnit.h:485
TInterface::TTClockxQuarterButtonClick
void __fastcall TTClockxQuarterButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13435
TTrainController::SSHigh
bool SSHigh
Definition: TrainUnit.h:756
TInterface::TextOrUserGraphicGridVal
int TextOrUserGraphicGridVal
stores the text alignment grid value, cycles forwards through 1, 2, 4, 8 & 16 each time the text grid...
Definition: InterfaceUnit.h:1145
TimeLoc
@ TimeLoc
Definition: TrainUnit.h:64
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:213
TInterface::FileMenu
TMenuItem * FileMenu
Definition: InterfaceUnit.h:417
TTrainController::AvHoursIntValue
int AvHoursIntValue
Input in MTBFEditBox in timetable hours, min value is 1 and max is 10,000. Here because performance f...
Definition: TrainUnit.h:806
TTrainController::CrashedTrains
int CrashedTrains
Definition: TrainUnit.h:778
TInterface::OutputLog3MouseDown
void __fastcall OutputLog3MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12693
TInterface::SpeedConversionPanel
TPanel * SpeedConversionPanel
Definition: InterfaceUnit.h:112
TTrainController::TTEditPanelVisible
bool TTEditPanelVisible
new at v2.6.0 so potential error message only shows in TTEdit mode
Definition: TrainUnit.h:754
TTrain::LogAction
void LogAction(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionType ActionType, AnsiString LocationName, TDateTime TimetableNonRepeatTime, bool Warning)
Send a message to the performance log and performance file, and if the message is flagged as a warnin...
Definition: TrainUnit.cpp:5068
TTextHandler::SaveText
void SaveText(int Caller, std::ofstream &VecFile)
save the railway's text to VecFile
Definition: TextUnit.cpp:335
TInterface::TwoLocationNameLabel
TLabel * TwoLocationNameLabel
Definition: InterfaceUnit.h:664
TTrain::StoppedAtSignal
bool StoppedAtSignal
Definition: TrainUnit.h:442
TTrack::GetGapHLoc
int GetGapHLoc()
Definition: TrackUnit.h:866
TInterface::ResetDefaultLengthButton
TBitBtn * ResetDefaultLengthButton
Definition: InterfaceUnit.h:84
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:142
TInterface::PauseEntryRestartTime
double PauseEntryRestartTime
time value of the timetable restart time (as a double) on entry to pause mode
Definition: InterfaceUnit.h:1081
TInterface::SelectBiDirPrefDirsMenuItemClick
void __fastcall SelectBiDirPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10708
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4188
TInterface::SigsOnRightImage2
TImage * SigsOnRightImage2
Definition: InterfaceUnit.h:291
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:808
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4533
TInterface::AddTrack
@ AddTrack
Definition: InterfaceUnit.h:903
TTrack::PlotSmallFlashingLinkedLevelCrossings
void PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
Plots either a LC or a blank element to flash manual LCs in zoomout mode.
Definition: TrackUnit.cpp:7426
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1935
TInterface::ClearAllMenuItem
TMenuItem * ClearAllMenuItem
Definition: InterfaceUnit.h:424
API
a class which handles the fetching of information from the ROS interface via pointers to variables of...
Definition: API.h:30
TTrainController::THCandTrainPosParam
std::pair< AnsiString, int > THCandTrainPosParam
Definition: TrainUnit.h:727
TInterface::SaveImageNoGridMenuItem
TMenuItem * SaveImageNoGridMenuItem
Definition: InterfaceUnit.h:460
TInterface::SelectMenuItemClick
void __fastcall SelectMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9554
TRailGraphics::SpeedBut74NormBlackGlyph
Graphics::TBitmap * SpeedBut74NormBlackGlyph
Definition: GraphicUnit.h:1052
TInterface::StartY
int StartY
the mouse position in terms of pixels when an item of text is being selected for moving
Definition: InterfaceUnit.h:1137
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:67
TInterface::UpdateOperatorActionPanel
void UpdateOperatorActionPanel(int Caller)
Called every 5 secs to update the panel (if visible)
Definition: InterfaceUnit.cpp:21056
TInterface::TextBoxKeyPress
void __fastcall TextBoxKeyPress(TObject *Sender, char &Key)
Definition: InterfaceUnit.cpp:1172
TInterface::SaveTimetableToSessionFile
bool SaveTimetableToSessionFile(int Caller, std::ofstream &SessionFile, AnsiString SessionFileStr)
Called during a session save to save the current timetable in the session file, true if successful.
Definition: InterfaceUnit.cpp:18864
TInterface::SpeedButton71
TSpeedButton * SpeedButton71
Definition: InterfaceUnit.h:583
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7221
TTrain::OpTimeToAct
float OpTimeToAct
in minutes: new at v2.2.0 for operator time to act panel. Calculated in UpdateTrain,...
Definition: TrainUnit.h:412
TInterface::DeleteAllPrefDirButtonClick
void __fastcall DeleteAllPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2071
Platform
@ Platform
Definition: TrackUnit.h:67
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1380
TInterface::RlyFile
bool RlyFile
indicates that a loaded railway file is ready for operation, i.e. is a valid .rly file
Definition: InterfaceUnit.h:1008
TInterface::RestartSessionOperMode
@ RestartSessionOperMode
Definition: InterfaceUnit.h:871
TInterface::PreferredRouteFlag
bool PreferredRouteFlag
used to select either ConvertAndAddPreferredRouteSearchVector or ConvertAndAddNonPreferredRouteSearch...
Definition: InterfaceUnit.h:1002
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:773
TInterface::TextMoveHPos
int TextMoveHPos
Definition: InterfaceUnit.h:1149
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4558
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:653
TInterface::PowerTopLabel
TLabel * PowerTopLabel
Definition: InterfaceUnit.h:194
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:784
TInterface::RepairFailedTrainMenuItem
TMenuItem * RepairFailedTrainMenuItem
Definition: InterfaceUnit.h:487
TUtilities::CheckAndCompareFileString
bool CheckAndCompareFileString(std::ifstream &InFile, AnsiString InString)
checks that the value is a string ('0' or CR accepted as delimiters) and is the same as InString,...
Definition: Utilities.cpp:474
TInterface::CutTTEntryButton
TButton * CutTTEntryButton
Definition: InterfaceUnit.h:137
TInterface::AZOrderKeyFlag
bool AZOrderKeyFlag
Definition: InterfaceUnit.h:1072
TInterface::MileEdit
TEdit * MileEdit
Definition: InterfaceUnit.h:104
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1304
TInterface::TTClockx8ButtonClick
void __fastcall TTClockx8ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13359
TInterface::SetLevel2OperMode
void SetLevel2OperMode(int Caller)
Sets the Level2OperMode user mode, using the Level2OperMode variable to determine the mode.
Definition: InterfaceUnit.cpp:15993
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9366
TInterface::RestoreTTButton
TButton * RestoreTTButton
Definition: InterfaceUnit.h:153
TTrain::TimetableFinished
bool TimetableFinished
set when there are no more timetable actions
Definition: TrainUnit.h:379
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1745
TInterface::EraseLocationNameText
bool EraseLocationNameText(int Caller, AnsiString Name, int &HPos, int &VPos)
Erase a location name (providing it exists in LocationNameMultiMap) from TextVector,...
Definition: InterfaceUnit.cpp:20886
TInterface::PrefDirKey
TImage * PrefDirKey
information panel displayed when setting preferred directions
Definition: InterfaceUnit.h:278
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:55
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:15722
TActionVectorEntry::Command
AnsiString Command
Definition: TrainUnit.h:103
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:810
TInterface::DeleteAllPrefDirButton
TBitBtn * DeleteAllPrefDirButton
Definition: InterfaceUnit.h:124
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:150
TTrain::SignallerStoppingFlag
bool SignallerStoppingFlag
set when the signaller stop command has been given
Definition: TrainUnit.h:371
TInterface::SelectPrefDir
TOnePrefDir * SelectPrefDir
Pref Dir elements in a selected region.
Definition: InterfaceUnit.h:1181
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:145
TTrack::BuildBasicElementFromSpeedTag
TTrackElement BuildBasicElementFromSpeedTag(int Caller, int SpeedTag)
Return a basic track element from the SpeedTag new at v2.2.0 - needed because Interface doesn't have ...
Definition: TrackUnit.h:921
TInterface::TTStartTimeBox
TEdit * TTStartTimeBox
edit box that displays the timetable start time
Definition: InterfaceUnit.h:177
TInterface::AddPrefDirButtonClick
void __fastcall AddPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2042
TInterface::ShiftKey
bool ShiftKey
true when the SHIFT key is pressed (see also CtrlKey)
Definition: InterfaceUnit.h:1022
TTrainController::SigSLow
bool SigSLow
Message flags in TT checks to stop being given twice.
Definition: TrainUnit.h:756
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:629
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6245
TInterface::AddMinsButtonClick
void __fastcall AddMinsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3701
RemoveTrain
@ RemoveTrain
Definition: TrainUnit.h:51
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3596
TInterface::FontButtonClick
void __fastcall FontButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1967
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:99
TInterface::SigAspectButtonClick
void __fastcall SigAspectButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1928
TInterface::SetLevel2TrackMode
void SetLevel2TrackMode(int Caller)
Sets the Level2TrackMode user mode, using the Level2TrackMode variable to determine the mode.
Definition: InterfaceUnit.cpp:15202
TTrainController::SetWarningFlags
void SetWarningFlags(int Caller)
This sets all the warning flags (CrashWarning, DerailWarning etc) to their required states after a se...
Definition: TrainUnit.cpp:19203
TInterface::TwoLocationNameButtonClick
void __fastcall TwoLocationNameButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14002
TInterface::None
@ None
Definition: InterfaceUnit.h:909
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:113
TInterface::FormClose
void __fastcall FormClose(TObject *Sender, TCloseAction &Action)
Definition: InterfaceUnit.cpp:12085
TInterface::SigAspectButton
TBitBtn * SigAspectButton
Definition: InterfaceUnit.h:81
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:10895
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:753
TInterface::PreviousTTEntryKeyFlag
bool PreviousTTEntryKeyFlag
Definition: InterfaceUnit.h:1063
TInterface::CPEditDepRange
TEdit * CPEditDepRange
Definition: InterfaceUnit.h:252
TTrainController::TotEarlyPassMins
float TotEarlyPassMins
Definition: TrainUnit.h:770
TTrainController::OpTimeToActMultiMap
TOpTimeToActMultiMap OpTimeToActMultiMap
added v2.2.0 for Op time to act display
Definition: TrainUnit.h:820
TInterface::SelectBitmapMouseLocY
int SelectBitmapMouseLocY
see above
Definition: InterfaceUnit.h:1127
TTrain::BrakeRate
double BrakeRate
the current train brake rate
Definition: TrainUnit.h:401
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:150
TPrefDirElement::SetCheckCount
void SetCheckCount(int ChkCnt)
Definition: TrackUnit.h:346
TTrack::GapFlashFlag
bool GapFlashFlag
true when a pair of connected gaps is flashing
Definition: TrackUnit.h:751
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:638
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:82
TInterface::StartX
int StartX
Definition: InterfaceUnit.h:1137
TrainUnit.h
TTrack::LevelCrossingBarrierUpFlashDuration
float LevelCrossingBarrierUpFlashDuration
duration of the flash period when level crossing closing to trains
Definition: TrackUnit.h:771
TTrainController::IncorrectExits
int IncorrectExits
Definition: TrainUnit.h:783
TUtilities::SetLocaleResultOK
bool SetLocaleResultOK
flag to indicate whether the call to setlocale() in InterfaceUnit.cpp succeeded or not
Definition: Utilities.h:42
TInterface::SelectLengthsFlag
bool SelectLengthsFlag
true when 'Set lengths &/or speeds' selected in the 'Edit' menu
Definition: InterfaceUnit.h:1018
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:91
TRailGraphics::LockedRouteCancelPtr
Graphics::TBitmap * LockedRouteCancelPtr[10]
for locked route cancel graphic, 1 for each of 8 links, 0 & 5 included as for direction
Definition: GraphicUnit.h:1038
TTextItem::TextString
AnsiString TextString
the text string
Definition: TextUnit.h:46
TInterface::TrackOKButton
TBitBtn * TrackOKButton
Definition: InterfaceUnit.h:71
TInterface::RailwayTitle
AnsiString RailwayTitle
Definition: InterfaceUnit.h:943
TDisplay::Rectangle
void Rectangle(int Caller, int HPos, int VPos, TColor Col, int Size, int Width)
Plot a rectangle at the defined position with colour Col & size defined by Size.
Definition: DisplayUnit.cpp:154
API.h
File containing classes and methods for broadcasting ROS status data.
TInterface::CheckInterface
bool CheckInterface(int Caller, std::ifstream &SessionFile)
Check the interface part of a session file & return false for error, called during SessionFileIntegri...
Definition: InterfaceUnit.cpp:18632
TInterface::PreStart
@ PreStart
Definition: InterfaceUnit.h:893
AboutForm
TAboutForm * AboutForm
Definition: AboutUnit.cpp:47
TInterface::ExitTTModeButton
TBitBtn * ExitTTModeButton
Definition: InterfaceUnit.h:131
TTrain::SetTrainMovementValues
void SetTrainMovementValues(int Caller, int TrackVectorPosition, int EntryPos)
Calculates train speeds and times for the element that the train is about to enter....
Definition: TrainUnit.cpp:3439
TActionVectorEntry::Warning
bool Warning
if set triggers an alert in the warning panel when the action is reached
Definition: TrainUnit.h:109
TInterface::OverallSpeedLimit
int OverallSpeedLimit
and the overall speed limit, if the speed limits vary across the selection the value is set to -1
Definition: InterfaceUnit.h:1115
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11360
TRailGraphics::SpeedBut75GrndBlackGlyph
Graphics::TBitmap * SpeedBut75GrndBlackGlyph
Definition: GraphicUnit.h:1061
TTrainDataEntry::ServiceReference
AnsiString ServiceReference
Definition: TrainUnit.h:188
TInterface::PowerEditBox
TEdit * PowerEditBox
Definition: InterfaceUnit.h:193
TInterface::TimetableHandler
void TimetableHandler()
Called during timetable editing whenever a change is made to the timetable, sets all the timetable bu...
Definition: InterfaceUnit.cpp:5420
TTrain::SignallerChangeTrainDirection
void SignallerChangeTrainDirection(int Caller)
Unplots & replots train, which checks for facing signal and sets StoppedAtSignal if req'd.
Definition: TrainUnit.cpp:6821
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:265
TInterface::CancelSelectionMenuItem
TMenuItem * CancelSelectionMenuItem
Definition: InterfaceUnit.h:449
TTrain::ZeroPowerNoRearSplitMessage
bool ZeroPowerNoRearSplitMessage
Definition: TrainUnit.h:311
TInterface::SpeedButton68
TSpeedButton * SpeedButton68
Definition: InterfaceUnit.h:580
TInterface::LoadSession
void LoadSession(int Caller)
Load a session file.
Definition: InterfaceUnit.cpp:18217
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:18516
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:88
TInterface::SigRouteStartMarker
TGraphicElement * SigRouteStartMarker
Definition: InterfaceUnit.h:1168
TInterface::SetGapsButtonClick
void __fastcall SetGapsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1113
TInterface::SignallerControlStopMenuItemClick
void __fastcall SignallerControlStopMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11744
TInterface::PrefDirSelecting
@ PrefDirSelecting
Definition: InterfaceUnit.h:898
TInterface::TimetableDialog
TOpenDialog * TimetableDialog
Definition: InterfaceUnit.h:498
TInterface::MissedTicks
unsigned int MissedTicks
missed clock ticks
Definition: InterfaceUnit.h:1101
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:10924
TInterface::MoveTTEntryUpButton
TButton * MoveTTEntryUpButton
Definition: InterfaceUnit.h:140
TInterface::SigPrefConsecButton
TBitBtn * SigPrefConsecButton
Definition: InterfaceUnit.h:202
TInterface::RotateMenuItem
TMenuItem * RotateMenuItem
Definition: InterfaceUnit.h:444
TInterface::TTClockxSixteenthButtonClick
void __fastcall TTClockxSixteenthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13473
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:688
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:533
TUtilities::Clock2Stopped
bool Clock2Stopped
when true the main loop - Interface->ClockTimer2 - is stopped
Definition: Utilities.h:38
TTrainController::MRSHigh
bool MRSHigh
Definition: TrainUnit.h:756
TInterface::FlipMenuItem
TMenuItem * FlipMenuItem
Definition: InterfaceUnit.h:442
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6146
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:159
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:68
TInterface::SessionFileIntegrityCheck
bool SessionFileIntegrityCheck(int Caller, AnsiString FileName)
Checks session file integrity prior to loading, true for success.
Definition: InterfaceUnit.cpp:19422
TInterface::TrainFailedImage
TImage * TrainFailedImage
Definition: InterfaceUnit.h:273
TTrain::NotInService
bool NotInService
Definition: TrainUnit.h:443
TInterface::RotLeftMenuItemClick
void __fastcall RotLeftMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10352
TInterface::ExitTrackButton
TBitBtn * ExitTrackButton
Definition: InterfaceUnit.h:82
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:745
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TInterface::OutputLog10
TLabel * OutputLog10
Definition: InterfaceUnit.h:309
TInterface::SESSION_DIR_NAME
static const UnicodeString SESSION_DIR_NAME
Definition: InterfaceUnit.h:885
TInterface::PasteTTEntryKeyFlag
bool PasteTTEntryKeyFlag
Definition: InterfaceUnit.h:1069
TInterface::FileChangedFlag
bool FileChangedFlag
true when a loaded railway file has changed (used to warn user if opts to exit without saving)
Definition: InterfaceUnit.h:976
TInterface::TooShortMessageSentFlag
bool TooShortMessageSentFlag
indicates that the length of a location element might be too short (<50m), so it won't be given again
Definition: InterfaceUnit.h:1038
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:144
TInterface::CutTTEntryButtonClick
void __fastcall CutTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3906
TInterface::AutoSigsButtonClick
void __fastcall AutoSigsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2193
TRailGraphics::SpeedBut69GrndBlackGlyph
Graphics::TBitmap * SpeedBut69GrndBlackGlyph
Definition: GraphicUnit.h:1055
Signaller
@ Signaller
Definition: TrainUnit.h:58
TRailGraphics::bmRedRect
Graphics::TBitmap * bmRedRect
Definition: GraphicUnit.h:527
TInterface::SaveOperatingImageMenuItemClick
void __fastcall SaveOperatingImageMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3008
TRailGraphics::smYellow
Graphics::TBitmap * smYellow
Definition: GraphicUnit.h:888
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TInterface::ConstructRoute
TOneRoute * ConstructRoute
the route under construction
Definition: InterfaceUnit.h:1183
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:10176
Bridge
@ Bridge
Definition: TrackUnit.h:67
TInterface::CutMenuItemClick
void __fastcall CutMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9646
TInterface::ResetCurrentSpeedButton
void ResetCurrentSpeedButton(int Caller)
Resets the CurrentSpeedButton variable to zero and the 'Down' property to false.
Definition: InterfaceUnit.cpp:14542
TTrain::TimetableMaxRunningSpeed
double TimetableMaxRunningSpeed
the maximum train running speed when in timetable mode (see int SignallerMaxSpeed for signaller contr...
Definition: TrainUnit.h:393
clB0G0R0
#define clB0G0R0
Definition: GraphicUnit.h:36
TInterface::CPDeparturesCheckBox
TCheckBox * CPDeparturesCheckBox
Definition: InterfaceUnit.h:249
Buffers
@ Buffers
Definition: TrackUnit.h:67
TInterface::SelectGraphic
@ SelectGraphic
Definition: InterfaceUnit.h:903
TTextHandler::TextMove
void TextMove(int Caller, int HPosInput, int VPosInput, int &TextItem, int &TextMoveHPos, int &TextMoveVPos, bool &TextFoundFlag)
Definition: TextUnit.cpp:209
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:50
clFrontCodeTimetable
#define clFrontCodeTimetable
Definition: GraphicUnit.h:296
TTrack::UserGraphicPresentAtHV
bool UserGraphicPresentAtHV(int Caller, int HPos, int VPos, int &UGIVectorPos)
checks if a user graphic present
Definition: TrackUnit.h:843
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:11384
TInterface::ExitTTModeButtonClick
void __fastcall ExitTTModeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4808
TInterface::MirrorMenuItemClick
void __fastcall MirrorMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9806
TInterface::RouteNotStarted
@ RouteNotStarted
Definition: InterfaceUnit.h:909
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4470
TInterface::SaveImageAndGridMenuItem
TMenuItem * SaveImageAndGridMenuItem
Definition: InterfaceUnit.h:461
TInterface::WhiteBgndMenuItemClick
void __fastcall WhiteBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12842
TInterface::GetTrainIDOrContinuationPosition
bool GetTrainIDOrContinuationPosition(int Caller, int X, int Y, int &TrainID, int &ContinuationPos)
Used in actions due panel to identify the train or continuation.
Definition: InterfaceUnit.cpp:5076